[PATCH v2 3/6] target/riscv: Add support for Control Transfer Records extension CSRs.

2024-06-19 Thread Rajnesh Kanwal
This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
sctrdepth CSRs handling.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.h |   5 ++
 target/riscv/cpu_cfg.h |   2 +
 target/riscv/csr.c | 128 +
 3 files changed, 135 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a185e2d494..3d4d5172b8 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -263,6 +263,11 @@ struct CPUArchState {
 target_ulong mcause;
 target_ulong mtval;  /* since: priv-1.10.0 */
 
+uint64_t mctrctl;
+uint32_t sctrdepth;
+uint32_t sctrstatus;
+uint64_t vsctrctl;
+
 /* Machine and Supervisor interrupt priorities */
 uint8_t miprio[64];
 uint8_t siprio[64];
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index d9354dc80a..d329a65811 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -123,6 +123,8 @@ struct RISCVCPUConfig {
 bool ext_zvfhmin;
 bool ext_smaia;
 bool ext_ssaia;
+bool ext_smctr;
+bool ext_ssctr;
 bool ext_sscofpmf;
 bool ext_smepmp;
 bool rvv_ta_all_1s;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 2f92e4b717..0b5bf4d050 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -621,6 +621,48 @@ static RISCVException pointer_masking(CPURISCVState *env, 
int csrno)
 return RISCV_EXCP_ILLEGAL_INST;
 }
 
+/*
+ * M-mode:
+ * Without ext_smctr raise illegal inst excep.
+ * Otherwise everything is accessible to m-mode.
+ *
+ * S-mode:
+ * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
+ * Otherwise everything other than mctrctl is accessible.
+ *
+ * VS-mode:
+ * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
+ * Without hstateen.ctr raise virtual illegal inst excep.
+ * Otherwise allow sctrctl (vsctrctl), sctrstatus, 0x200-0x2ff entry range.
+ * Always raise illegal instruction exception for sctrdepth.
+ */
+static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
+{
+/* Check if smctr-ext is present */
+if (riscv_cpu_cfg(env)->ext_smctr) {
+return RISCV_EXCP_NONE;
+}
+
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException ctr_smode(CPURISCVState *env, int csrno)
+{
+const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
+
+if (!cfg->ext_smctr && !cfg->ext_ssctr) {
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
+if (ret == RISCV_EXCP_NONE && csrno == CSR_SCTRDEPTH &&
+env->virt_enabled) {
+return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+}
+
+return ret;
+}
+
 static RISCVException aia_hmode(CPURISCVState *env, int csrno)
 {
 int ret;
@@ -3835,6 +3877,86 @@ static RISCVException write_satp(CPURISCVState *env, int 
csrno,
 return RISCV_EXCP_NONE;
 }
 
+static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
+target_ulong *ret_val,
+target_ulong new_val, target_ulong wr_mask)
+{
+uint64_t mask = wr_mask & SCTRDEPTH_MASK;
+
+if (ret_val) {
+*ret_val = env->sctrdepth;
+}
+
+env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
+
+/* Correct depth. */
+if (wr_mask & SCTRDEPTH_MASK) {
+uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
+
+if (depth > SCTRDEPTH_MAX) {
+depth = SCTRDEPTH_MAX;
+env->sctrdepth = set_field(env->sctrdepth, SCTRDEPTH_MASK, depth);
+}
+
+/* Update sctrstatus.WRPTR with a legal value */
+depth = 16 << depth;
+env->sctrstatus =
+env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
+}
+
+return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_sctrstatus(CPURISCVState *env, int csrno,
+ target_ulong *ret_val,
+ target_ulong new_val, target_ulong 
wr_mask)
+{
+uint32_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
+uint32_t mask = wr_mask & SCTRSTATUS_MASK;
+
+if (ret_val) {
+*ret_val = env->sctrstatus;
+}
+
+env->sctrstatus = (env->sctrstatus & ~mask) | (new_val & mask);
+
+/* Update sctrstatus.WRPTR with a legal value */
+env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
+
+return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_xctrctl(CPURISCVState *env, int csrno,
+target_ulong *ret_val,
+target_ulong new_val, target_ulong wr_mask)
+{
+uint64_t csr_mask, mask = wr_mask;
+uint64_t *ctl_ptr = >mctrctl;
+
+if (csrno == CSR_MCTRCTL) {
+csr_mask = MCTRCTL_MASK;
+} else if (csrno == CSR_SCTRCTL && !env->virt_enabled) {
+csr

[PATCH v2 5/6] target/riscv: Add CTR sctrclr instruction.

2024-06-19 Thread Rajnesh Kanwal
CTR extension adds a new instruction sctrclr to quickly
clear the recorded entries buffer.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.h|  1 +
 target/riscv/cpu_helper.c |  7 
 target/riscv/helper.h |  1 +
 target/riscv/insn32.decode|  1 +
 .../riscv/insn_trans/trans_privileged.c.inc   | 10 ++
 target/riscv/op_helper.c  | 33 +++
 6 files changed, 53 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index e32f5ab146..fdc18a782a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -572,6 +572,7 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong 
newpriv, bool virt_en);
 void riscv_ctr_freeze(CPURISCVState *env, uint64_t freeze_mask, bool virt);
 void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
  uint64_t type, target_ulong prev_priv, bool 
prev_virt);
+void riscv_ctr_clear(CPURISCVState *env);
 
 void riscv_translate_init(void);
 G_NORETURN void riscv_raise_exception(CPURISCVState *env,
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 1537602e1b..d98628cfe3 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -702,6 +702,13 @@ void riscv_ctr_freeze(CPURISCVState *env, uint64_t 
freeze_mask, bool virt)
 }
 }
 
+void riscv_ctr_clear(CPURISCVState *env)
+{
+memset(env->ctr_src, 0x0, sizeof(env->ctr_src));
+memset(env->ctr_dst, 0x0, sizeof(env->ctr_dst));
+memset(env->ctr_data, 0x0, sizeof(env->ctr_data));
+}
+
 static uint64_t riscv_ctr_priv_to_mask(target_ulong priv, bool virt)
 {
 switch (priv) {
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index b8fb7c8734..a3b2d87527 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_2(sret, tl, env, tl)
 DEF_HELPER_2(mret, tl, env, tl)
+DEF_HELPER_1(ctr_clear, void, 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 9cb1a1b4ec..d3d38c7c68 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -107,6 +107,7 @@
 # *** Privileged Instructions ***
 ecall    0 000 0 1110011
 ebreak  0001 0 000 0 1110011
+sctrclr 00010100 0 000 0 1110011
 uret00000010 0 000 0 1110011
 sret000100000010 0 000 0 1110011
 mret001100000010 0 000 0 1110011
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc 
b/target/riscv/insn_trans/trans_privileged.c.inc
index 339d659151..dd9da8651f 100644
--- a/target/riscv/insn_trans/trans_privileged.c.inc
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -69,6 +69,16 @@ static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
 return true;
 }
 
+static bool trans_sctrclr(DisasContext *ctx, arg_sctrclr *a)
+{
+#ifndef CONFIG_USER_ONLY
+gen_helper_ctr_clear(tcg_env);
+return true;
+#else
+return false;
+#endif
+}
+
 static bool trans_uret(DisasContext *ctx, arg_uret *a)
 {
 return false;
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 5a1e92c45e..15a770360e 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -475,6 +475,39 @@ void helper_ctr_branch(CPURISCVState *env, target_ulong 
src, target_ulong dest,
 }
 }
 
+void helper_ctr_clear(CPURISCVState *env)
+{
+if (!riscv_cpu_cfg(env)->ext_ssctr && !riscv_cpu_cfg(env)->ext_smctr) {
+riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
+}
+
+/*
+ * It's safe to call smstateen_acc_ok() for umode access regardless of the
+ * state of bit 54 (CTR bit in case of m/hstateen) of sstateen. If the bit
+ * is zero, smstateen_acc_ok() will return the correct exception code and
+ * if it's one, smstateen_acc_ok() will return RISCV_EXCP_NONE. In that
+ * scenario the U-mode check below will handle that case.
+ */
+RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
+if (ret != RISCV_EXCP_NONE) {
+riscv_raise_exception(env, ret, GETPC());
+}
+
+if (env->priv == PRV_U) {
+/*
+ * One corner case is when sctrclr is executed from VU-mode and
+ * mstateen.CTR = 0, in which case we are supposed to raise
+ * RISCV_EXCP_ILLEGAL_INST. This case is already handled in
+ * smstateen_acc_ok().
+ */
+uint32_t excep = env->virt_enabled ? RISCV_EXCP_VIRT_INSTRUCTION_FAULT 
:
+RISCV_EXCP_ILLEGAL_INST;
+riscv_raise_exception(env, excep, GETPC());
+}
+
+riscv_ctr_clear(env);
+}
+
 void helper_wfi(CPURISCVState *env)
 {
 CPUState *cs = env_cpu(env);
-- 
2.34.1




[PATCH v2 6/6] target/riscv: Add support to access ctrsource, ctrtarget, ctrdata regs.

2024-06-19 Thread Rajnesh Kanwal
CTR entries are accessed using ctrsource, ctrtarget and ctrdata
registers using smcsrind/sscsrind extension. This commits extends
the csrind extension to support CTR registers.

ctrsource is accessible through xireg CSR, ctrtarget is accessible
through xireg1 and ctrdata is accessible through xireg2 CSR.

CTR supports maximum depth of 256 entries which are accessed using
xiselect range 0x200 to 0x2ff.

This commits also adds properties to enable CTR extension. CTR can be
enabled using smctr=true and ssctr=true now.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.c |   4 +
 target/riscv/csr.c | 148 -
 target/riscv/tcg/tcg-cpu.c |   6 ++
 3 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 30bdfc22ae..a77b1d5caf 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -193,6 +193,8 @@ const RISCVIsaExtData isa_edata_arr[] = {
 ISA_EXT_DATA_ENTRY(sstvala, PRIV_VERSION_1_12_0, has_priv_1_12),
 ISA_EXT_DATA_ENTRY(sstvecd, PRIV_VERSION_1_12_0, has_priv_1_12),
 ISA_EXT_DATA_ENTRY(svade, PRIV_VERSION_1_11_0, ext_svade),
+ISA_EXT_DATA_ENTRY(smctr, PRIV_VERSION_1_12_0, ext_smctr),
+ISA_EXT_DATA_ENTRY(ssctr, PRIV_VERSION_1_12_0, ext_ssctr),
 ISA_EXT_DATA_ENTRY(svadu, PRIV_VERSION_1_12_0, ext_svadu),
 ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval),
 ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot),
@@ -1473,6 +1475,8 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
 MULTI_EXT_CFG_BOOL("sscsrind", ext_sscsrind, false),
 MULTI_EXT_CFG_BOOL("smcdeleg", ext_smcdeleg, false),
 MULTI_EXT_CFG_BOOL("ssccfg", ext_ssccfg, false),
+MULTI_EXT_CFG_BOOL("smctr", ext_smctr, false),
+MULTI_EXT_CFG_BOOL("ssctr", ext_ssctr, false),
 MULTI_EXT_CFG_BOOL("zifencei", ext_zifencei, true),
 MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true),
 MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true),
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 0b5bf4d050..3ed9f95a4f 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2278,6 +2278,13 @@ static bool xiselect_cd_range(target_ulong isel)
 return (ISELECT_CD_FIRST <= isel && isel <= ISELECT_CD_LAST);
 }
 
+static bool xiselect_ctr_range(int csrno, target_ulong isel)
+{
+/* MIREG-MIREG6 for the range 0x200-0x2ff are not used by CTR. */
+return CTR_ENTRIES_FIRST <= isel && isel <= CTR_ENTRIES_LAST &&
+   csrno < CSR_MIREG;
+}
+
 static int rmw_iprio(target_ulong xlen,
  target_ulong iselect, uint8_t *iprio,
  target_ulong *val, target_ulong new_val,
@@ -2323,6 +2330,124 @@ static int rmw_iprio(target_ulong xlen,
 return 0;
 }
 
+static int rmw_ctrsource(CPURISCVState *env, int isel, target_ulong *val,
+  target_ulong new_val, target_ulong wr_mask)
+{
+/*
+ * CTR arrays are treated as circular buffers and TOS always points to next
+ * empty slot, keeping TOS - 1 always pointing to latest entry. Given entry
+ * 0 is always the latest one, traversal is a bit different here. See the
+ * below example.
+ *
+ * Depth = 16.
+ *
+ * idx[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [A] [B] [C] [D] [E] [F]
+ * TOS H
+ * entry   6   5   4   3   2   1   0   F   E   D   C   B   A   9   8   7
+ */
+const uint64_t entry = isel - CTR_ENTRIES_FIRST;
+const uint64_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
+uint64_t idx;
+
+/* Entry greater than depth-1 is read-only zero */
+if (entry >= depth) {
+if (val) {
+*val = 0;
+}
+return 0;
+}
+
+idx = get_field(env->sctrstatus, SCTRSTATUS_WRPTR_MASK);
+idx = (idx - entry - 1) & (depth - 1);
+
+if (val) {
+*val = env->ctr_src[idx];
+}
+
+env->ctr_src[idx] = (env->ctr_src[idx] & ~wr_mask) | (new_val & wr_mask);
+
+return 0;
+}
+
+static int rmw_ctrtarget(CPURISCVState *env, int isel, target_ulong *val,
+  target_ulong new_val, target_ulong wr_mask)
+{
+/*
+ * CTR arrays are treated as circular buffers and TOS always points to next
+ * empty slot, keeping TOS - 1 always pointing to latest entry. Given entry
+ * 0 is always the latest one, traversal is a bit different here. See the
+ * below example.
+ *
+ * Depth = 16.
+ *
+ * idx[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [A] [B] [C] [D] [E] [F]
+ * headH
+ * entry   6   5   4   3   2   1   0   F   E   D   C   B   A   9   8   7
+ */
+const uint64_t entry = isel - CTR_ENTRIES_FIRST;
+const uint64_t depth = 16 << get_field(env->sctrdepth

[PATCH v2 0/6] target/riscv: Add support for Control Transfer Records Ext.

2024-06-19 Thread Rajnesh Kanwal
This series enables Control Transfer Records extension support on riscv
platform. This extension is similar to Arch LBR in x86 and BRBE in ARM.
The Extension has been stable and the latest release can be found here [0]

CTR extension depends on couple of other extensions:

1. S[m|s]csrind : The indirect CSR extension [1] which defines additional
   ([M|S|VS]IREG2-[M|S|VS]IREG6) register to address size limitation of
   RISC-V CSR address space. CTR access ctrsource, ctrtartget and ctrdata
   CSRs using sscsrind extension.

2. Smstateen: The mstateen bit[54] controls the access to the CTR ext to
   S-mode.

3. Sscofpmf: Counter overflow and privilege mode filtering. [2]

The series is based on Smcdeleg/Ssccfg counter delegation extension [3]
patches. CTR itself doesn't depend on counter delegation support. This
rebase is basically to include the Smcsrind patches.

Due to the dependency of these extensions, the following extensions must be
enabled to use the control transfer records feature.

"smstateen=true,sscofpmf=true,smcsrind=true,sscsrind=true,smctr=true,ssctr=true"

Here is the link to a quick guide [5] to setup and run a basic perf demo on
Linux to use CTR Ext.

The Qemu patches can be found here:
https://github.com/rajnesh-kanwal/qemu/tree/ctr_upstream_v2

The opensbi patch can be found here:
https://github.com/rajnesh-kanwal/opensbi/tree/ctr_upstream_v2

The Linux kernel patches can be found here:
https://github.com/rajnesh-kanwal/linux/tree/ctr_upstream_v2

[0]: https://github.com/riscv/riscv-control-transfer-records/release
[1]: https://github.com/riscv/riscv-indirect-csr-access
[2]: https://github.com/riscvarchive/riscv-count-overflow/tree/main
[3]: https://github.com/riscv/riscv-smcdeleg-ssccfg
[4]: https://lore.kernel.org/all/20240217000134.3634191-1-ati...@rivosinc.com/
[5]: 
https://github.com/rajnesh-kanwal/linux/wiki/Running-CTR-basic-demo-on-QEMU-RISC%E2%80%90V-Virt-machine

Changelog:

v2: Lots of improvements based on Jason Chien's feedback including:
  - Added CTR recording for cm.jalt, cm.jt, cm.popret, cm.popretz.
  - Fixed and added more CTR extension enable checks.
  - Fixed CTR CSR predicate functions.
  - Fixed external trap xTE bit checks.
  - One fix in freeze function for VS-mode.
  - Lots of minor code improvements.
  - Added checks in sctrclr instruction helper.

v1:
  - https://github.com/rajnesh-kanwal/qemu/tree/ctr_upstream


Rajnesh Kanwal (6):
  target/riscv: Remove obsolete sfence.vm instruction
  target/riscv: Add Control Transfer Records CSR definitions.
  target/riscv: Add support for Control Transfer Records extension CSRs.
  target/riscv: Add support to record CTR entries.
  target/riscv: Add CTR sctrclr instruction.
  target/riscv: Add support to access ctrsource, ctrtarget, ctrdata
regs.

 target/riscv/cpu.c|   4 +
 target/riscv/cpu.h|  14 +
 target/riscv/cpu_bits.h   | 154 ++
 target/riscv/cpu_cfg.h|   2 +
 target/riscv/cpu_helper.c | 265 +
 target/riscv/csr.c| 276 +-
 target/riscv/helper.h |   9 +-
 target/riscv/insn32.decode|   2 +-
 .../riscv/insn_trans/trans_privileged.c.inc   |  21 +-
 target/riscv/insn_trans/trans_rvi.c.inc   |  31 ++
 target/riscv/insn_trans/trans_rvzce.c.inc |  20 ++
 target/riscv/op_helper.c  | 159 +-
 target/riscv/tcg/tcg-cpu.c|   6 +
 target/riscv/translate.c  |  10 +
 14 files changed, 960 insertions(+), 13 deletions(-)

-- 
2.34.1




[PATCH v2 4/6] target/riscv: Add support to record CTR entries.

2024-06-19 Thread Rajnesh Kanwal
This commit adds logic to records CTR entries of different types
and adds required hooks in TCG and interrupt/Exception logic to
record events.

This commit also adds support to invoke freeze CTR logic for breakpoint
exceptions and counter overflow interrupts.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.h|   8 +
 target/riscv/cpu_helper.c | 258 ++
 target/riscv/helper.h |   8 +-
 .../riscv/insn_trans/trans_privileged.c.inc   |   6 +-
 target/riscv/insn_trans/trans_rvi.c.inc   |  31 +++
 target/riscv/insn_trans/trans_rvzce.c.inc |  20 ++
 target/riscv/op_helper.c  | 126 -
 target/riscv/translate.c  |  10 +
 8 files changed, 461 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 3d4d5172b8..e32f5ab146 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -268,6 +268,10 @@ struct CPUArchState {
 uint32_t sctrstatus;
 uint64_t vsctrctl;
 
+uint64_t ctr_src[16 << SCTRDEPTH_MAX];
+uint64_t ctr_dst[16 << SCTRDEPTH_MAX];
+uint64_t ctr_data[16 << SCTRDEPTH_MAX];
+
 /* Machine and Supervisor interrupt priorities */
 uint8_t miprio[64];
 uint8_t siprio[64];
@@ -565,6 +569,10 @@ RISCVException smstateen_acc_ok(CPURISCVState *env, int 
index, uint64_t bit);
 #endif
 void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool 
virt_en);
 
+void riscv_ctr_freeze(CPURISCVState *env, uint64_t freeze_mask, bool virt);
+void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
+ uint64_t type, target_ulong prev_priv, bool 
prev_virt);
+
 void riscv_translate_init(void);
 G_NORETURN void riscv_raise_exception(CPURISCVState *env,
   uint32_t exception, uintptr_t pc);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index a441a03ef4..1537602e1b 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -691,6 +691,246 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, 
uint32_t priv,
 }
 }
 
+void riscv_ctr_freeze(CPURISCVState *env, uint64_t freeze_mask, bool virt)
+{
+uint64_t ctl = virt ? env->mctrctl : env->vsctrctl;
+
+assert((freeze_mask & (~(MCTRCTL_BPFRZ | MCTRCTL_LCOFIFRZ))) == 0);
+
+if (ctl & freeze_mask) {
+env->sctrstatus |= SCTRSTATUS_FROZEN;
+}
+}
+
+static uint64_t riscv_ctr_priv_to_mask(target_ulong priv, bool virt)
+{
+switch (priv) {
+case PRV_M:
+return MCTRCTL_M_ENABLE;
+case PRV_S:
+if (virt) {
+return VSCTRCTL_VS_ENABLE;
+}
+return MCTRCTL_S_ENABLE;
+case PRV_U:
+if (virt) {
+return VSCTRCTL_VU_ENABLE;
+}
+return MCTRCTL_U_ENABLE;
+}
+
+g_assert_not_reached();
+}
+
+static uint64_t riscv_ctr_get_control(CPURISCVState *env, target_long priv,
+  bool virt)
+{
+switch (priv) {
+case PRV_M:
+return env->mctrctl;
+case PRV_S:
+case PRV_U:
+if (virt) {
+return env->vsctrctl;
+}
+return env->mctrctl;
+}
+
+g_assert_not_reached();
+}
+
+/*
+ * This function assumes that src privilege and target privilege are not same
+ * and src privilege is less than target privilege. This includes the virtual
+ * state as well.
+ */
+static bool riscv_ctr_check_xte(CPURISCVState *env, target_long src_prv,
+bool src_virt)
+{
+target_long tgt_prv = env->priv;
+bool res = true;
+
+/*
+ * VS and U mode are same in terms of xTE bits required to record an
+ * external trap. See 6.1.2. External Traps, table 8 External Trap Enable
+ * Requirements. This changes VS to U to simplify the logic a bit.
+ */
+if (src_virt && src_prv == PRV_S) {
+src_prv = PRV_U;
+} else if (env->virt_enabled && tgt_prv == PRV_S) {
+tgt_prv = PRV_U;
+}
+
+/* VU mode is an outlier here. */
+if (src_virt && src_prv == PRV_U) {
+res &= !!(env->vsctrctl & VSCTRCTL_VSTE);
+}
+
+switch (src_prv) {
+case PRV_U:
+if (tgt_prv == PRV_U) {
+break;
+}
+res &= !!(env->mctrctl & SCTRCTL_STE);
+/* fall-through */
+case PRV_S:
+if (tgt_prv == PRV_S) {
+break;
+}
+res &= !!(env->mctrctl & MCTRCTL_MTE);
+/* fall-through */
+case PRV_M:
+break;
+}
+
+return res;
+}
+
+/*
+ * Special cases for traps and trap returns:
+ *
+ * 1- Traps, and trap returns, between enabled modes are recorded as normal.
+ * 2- Traps from an inhibited mode to an enabled mode, and trap returns from an
+ * enabled mode back to an inhibited mode, are partially recorded.  In such
+ * case

[PATCH v2 2/6] target/riscv: Add Control Transfer Records CSR definitions.

2024-06-19 Thread Rajnesh Kanwal
The Control Transfer Records (CTR) extension provides a method to
record a limited branch history in register-accessible internal chip
storage.

This extension is similar to Arch LBR in x86 and BRBE in ARM.
The Extension has been stable and the latest release can be found here
https://github.com/riscv/riscv-control-transfer-records/release

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu_bits.h | 154 
 1 file changed, 154 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 86e15381c8..71ddccaf1a 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -242,6 +242,17 @@
 #define CSR_SIEH0x114
 #define CSR_SIPH0x154
 
+/* Machine-Level Control transfer records CSRs */
+#define CSR_MCTRCTL 0x34e
+
+/* Supervisor-Level Control transfer records CSRs */
+#define CSR_SCTRCTL 0x14e
+#define CSR_SCTRSTATUS  0x14f
+#define CSR_SCTRDEPTH   0x15f
+
+/* VS-Level Control transfer records CSRs */
+#define CSR_VSCTRCTL0x24e
+
 /* Hpervisor CSRs */
 #define CSR_HSTATUS 0x600
 #define CSR_HEDELEG 0x602
@@ -339,6 +350,7 @@
 #define SMSTATEEN0_CS   (1ULL << 0)
 #define SMSTATEEN0_FCSR (1ULL << 1)
 #define SMSTATEEN0_JVT  (1ULL << 2)
+#define SMSTATEEN0_CTR  (1ULL << 54)
 #define SMSTATEEN0_HSCONTXT (1ULL << 57)
 #define SMSTATEEN0_IMSIC(1ULL << 58)
 #define SMSTATEEN0_AIA  (1ULL << 59)
@@ -854,6 +866,148 @@ typedef enum RISCVException {
 #define UMTE_U_PM_INSN  U_PM_INSN
 #define UMTE_MASK (UMTE_U_PM_ENABLE | MMTE_U_PM_CURRENT | UMTE_U_PM_INSN)
 
+/* mctrctl CSR bits. */
+#define MCTRCTL_U_ENABLEBIT(0)
+#define MCTRCTL_S_ENABLEBIT(1)
+#define MCTRCTL_M_ENABLEBIT(2)
+#define MCTRCTL_RASEMU  BIT(7)
+#define MCTRCTL_STE BIT(8)
+#define MCTRCTL_MTE BIT(9)
+#define MCTRCTL_BPFRZ   BIT(11)
+#define MCTRCTL_LCOFIFRZBIT(12)
+#define MCTRCTL_EXCINH  BIT(33)
+#define MCTRCTL_INTRINH BIT(34)
+#define MCTRCTL_TRETINH BIT(35)
+#define MCTRCTL_NTBREN  BIT(36)
+#define MCTRCTL_TKBRINH BIT(37)
+#define MCTRCTL_INDCALL_INH BIT(40)
+#define MCTRCTL_DIRCALL_INH BIT(41)
+#define MCTRCTL_INDJUMP_INH BIT(42)
+#define MCTRCTL_DIRJUMP_INH BIT(43)
+#define MCTRCTL_CORSWAP_INH BIT(44)
+#define MCTRCTL_RET_INH BIT(45)
+#define MCTRCTL_INDOJUMP_INHBIT(46)
+#define MCTRCTL_DIROJUMP_INHBIT(47)
+
+#define MCTRCTL_INH_START   32U
+
+#define MCTRCTL_MASK (MCTRCTL_M_ENABLE | MCTRCTL_S_ENABLE |   \
+  MCTRCTL_U_ENABLE | MCTRCTL_RASEMU | \
+  MCTRCTL_MTE | MCTRCTL_STE | \
+  MCTRCTL_BPFRZ | MCTRCTL_LCOFIFRZ |  \
+  MCTRCTL_EXCINH | MCTRCTL_INTRINH |  \
+  MCTRCTL_TRETINH | MCTRCTL_NTBREN |  \
+  MCTRCTL_TKBRINH | MCTRCTL_INDCALL_INH | \
+  MCTRCTL_DIRCALL_INH | MCTRCTL_INDJUMP_INH | \
+  MCTRCTL_DIRJUMP_INH | MCTRCTL_CORSWAP_INH | \
+  MCTRCTL_RET_INH | MCTRCTL_INDOJUMP_INH |\
+  MCTRCTL_DIROJUMP_INH)
+
+/* sctrctl CSR bits. */
+#define SCTRCTL_U_ENABLE  MCTRCTL_U_ENABLE
+#define SCTRCTL_S_ENABLE  MCTRCTL_S_ENABLE
+#define SCTRCTL_RASEMUMCTRCTL_RASEMU
+#define SCTRCTL_STE   MCTRCTL_STE
+#define SCTRCTL_BPFRZ MCTRCTL_BPFRZ
+#define SCTRCTL_LCOFIFRZ  MCTRCTL_LCOFIFRZ
+#define SCTRCTL_EXCINHMCTRCTL_EXCINH
+#define SCTRCTL_INTRINH   MCTRCTL_INTRINH
+#define SCTRCTL_TRETINH   MCTRCTL_TRETINH
+#define SCTRCTL_NTBRENMCTRCTL_NTBREN
+#define SCTRCTL_TKBRINH   MCTRCTL_TKBRINH
+#define SCTRCTL_INDCALL_INH   MCTRCTL_INDCALL_INH
+#define SCTRCTL_DIRCALL_INH   MCTRCTL_DIRCALL_INH
+#define SCTRCTL_INDJUMP_INH   MCTRCTL_INDJUMP_INH
+#define SCTRCTL_DIRJUMP_INH   MCTRCTL_DIRJUMP_INH
+#define SCTRCTL_CORSWAP_INH   MCTRCTL_CORSWAP_INH
+#define SCTRCTL_RET_INH   MCTRCTL_RET_INH
+#define SCTRCTL_INDOJUMP_INH  MCTRCTL_INDOJUMP_INH
+#define SCTRCTL_DIROJUMP_INH  MCTRCTL_DIROJUMP_INH
+
+#define SCTRCTL_MASK (SCTRCTL_S_ENABLE | SCTRCTL_U_ENABLE |   \
+  SCTRCTL_RASEMU | SCTRCTL_STE |  \
+  SCTRCTL_BPFRZ | SCTRCTL_LCOFIFRZ |  \
+  SCTRCTL_EXCINH | SCTRCTL_INTRINH |  \
+  SCTRCTL_TRETINH | SCTRCTL_NTBREN |  \
+  SCTRCTL_TKBRINH | SCTRCTL_INDCALL_INH | \
+  SCTRCTL_DIRCALL_INH | SCTRCTL_INDJUMP_INH | \
+  SCTRCTL_DIRJUMP_INH | SCTRCTL_CORSWAP_INH | \
+  SCTRCTL_RET_INH | SCTRCTL_INDOJUMP_INH |\
+

[PATCH v2 1/6] target/riscv: Remove obsolete sfence.vm instruction

2024-06-19 Thread Rajnesh Kanwal
Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/insn32.decode | 1 -
 target/riscv/insn_trans/trans_privileged.c.inc | 5 -
 2 files changed, 6 deletions(-)

diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index f22df04cfd..9cb1a1b4ec 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -112,7 +112,6 @@ sret000100000010 0 000 0 1110011
 mret001100000010 0 000 0 1110011
 wfi 000100000101 0 000 0 1110011
 sfence_vma  0001001. . 000 0 1110011 @sfence_vma
-sfence_vm   000100000100 . 000 0 1110011 @sfence_vm
 
 # *** 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 bc5263a4e0..4eccdddeaa 100644
--- a/target/riscv/insn_trans/trans_privileged.c.inc
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -127,8 +127,3 @@ static bool trans_sfence_vma(DisasContext *ctx, 
arg_sfence_vma *a)
 #endif
 return false;
 }
-
-static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
-{
-return false;
-}
-- 
2.34.1




Re: [PATCH 3/6] target/riscv: Add support for Control Transfer Records extension CSRs.

2024-06-10 Thread Rajnesh Kanwal
Thanks Jason for your review.

On Tue, Jun 4, 2024 at 11:14 AM Jason Chien  wrote:
>
>
> Rajnesh Kanwal 於 2024/5/30 上午 12:09 寫道:
>
> This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
> sctrdepth CSRs handling.
>
> Signed-off-by: Rajnesh Kanwal 
> ---
>  target/riscv/cpu.h |   5 ++
>  target/riscv/cpu_cfg.h |   2 +
>  target/riscv/csr.c | 159 +
>  3 files changed, 166 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index a185e2d494..3d4d5172b8 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -263,6 +263,11 @@ struct CPUArchState {
>  target_ulong mcause;
>  target_ulong mtval;  /* since: priv-1.10.0 */
>
> +uint64_t mctrctl;
> +uint32_t sctrdepth;
> +uint32_t sctrstatus;
> +uint64_t vsctrctl;
> +
>  /* Machine and Supervisor interrupt priorities */
>  uint8_t miprio[64];
>  uint8_t siprio[64];
> diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
> index d9354dc80a..d329a65811 100644
> --- a/target/riscv/cpu_cfg.h
> +++ b/target/riscv/cpu_cfg.h
> @@ -123,6 +123,8 @@ struct RISCVCPUConfig {
>  bool ext_zvfhmin;
>  bool ext_smaia;
>  bool ext_ssaia;
> +bool ext_smctr;
> +bool ext_ssctr;
>  bool ext_sscofpmf;
>  bool ext_smepmp;
>  bool rvv_ta_all_1s;
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 2f92e4b717..888084d8e5 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -621,6 +621,61 @@ static RISCVException pointer_masking(CPURISCVState
*env, int csrno)
>  return RISCV_EXCP_ILLEGAL_INST;
>  }
>
> +/*
> + * M-mode:
> + * Without ext_smctr raise illegal inst excep.
> + * Otherwise everything is accessible to m-mode.
> + *
> + * S-mode:
> + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> + * Otherwise everything other than mctrctl is accessible.
> + *
> + * VS-mode:
> + * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
> + * Without hstateen.ctr raise virtual illegal inst excep.
> + * Otherwise allow vsctrctl, sctrstatus, 0x200-0x2ff entry range.
> + * Always raise illegal instruction exception for sctrdepth.
> + */
> +static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
> +{
> +/* Check if smctr-ext is present */
> +if (riscv_cpu_cfg(env)->ext_smctr) {
> +return RISCV_EXCP_NONE;
> +}
> +
> +return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
> +static RISCVException ctr_smode(CPURISCVState *env, int csrno)
> +{
> +if ((env->priv == PRV_M && riscv_cpu_cfg(env)->ext_smctr) ||
> +(env->priv == PRV_S && !env->virt_enabled &&
> + riscv_cpu_cfg(env)->ext_ssctr)) {
> +return smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
> +}
> +
> +if (env->priv == PRV_S && env->virt_enabled &&
> +riscv_cpu_cfg(env)->ext_ssctr) {
> +if (csrno == CSR_SCTRSTATUS) {
>
> missing sctrctl?
>
> +return smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
> +}
> +
> +return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +}
> +
> +return RISCV_EXCP_ILLEGAL_INST;
> +}
>
> I think there is no need to bind M-mode with ext_smctr, S-mode with
ext_ssctr and VS-mode with ext_ssctr, since this predicate function is for
S-mode CSRs, which are defined in both smctr and ssctr, we just need to
check at least one of ext_ssctr or ext_smctr is true.
>
> The spec states that:
> Attempts to access sctrdepth from VS-mode or VU-mode raise a
virtual-instruction exception, unless CTR state enable access restrictions
apply.
>
> In my understanding, we should check the presence of smstateen extension
first, and
>
> if smstateen is implemented:
>
> for sctrctl and sctrstatus, call smstateen_acc_ok()
> for sctrdepth, call smstateen_acc_ok(), and if there is any exception
returned, always report virtual-instruction exception.

For sctrdepth, we are supposed to always return a virt-inst exception in
case of
VS-VU mode unless CTR state enable access restrictions apply.

So for sctrdepth, call smstateen_acc_ok(), and if there is no exception
returned
(mstateen.CTR=1 and hstateen.CTR=1 for virt mode), check if we are in
virtual
mode and return virtual-instruction exception otherwise return
RISCV_EXCP_NONE.
Note that if hstateen.CTR=0, smstateen_acc_ok() will return
virtual-instruction
exception which means regardless of the hstateen.CTR state, we will always
return virtual-instruction exception for VS/VU mode access to sctrdepth.

Basically this covers following rules for sctrdepth:

if mstateen.ctr == 0
return RISCV_EXCP_ILLEGAL_INST; // For all 

[PATCH 1/6] target/riscv: Remove obsolete sfence.vm instruction

2024-05-29 Thread Rajnesh Kanwal
Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/insn32.decode | 1 -
 target/riscv/insn_trans/trans_privileged.c.inc | 5 -
 2 files changed, 6 deletions(-)

diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index f22df04cfd..9cb1a1b4ec 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -112,7 +112,6 @@ sret000100000010 0 000 0 1110011
 mret001100000010 0 000 0 1110011
 wfi 000100000101 0 000 0 1110011
 sfence_vma  0001001. . 000 0 1110011 @sfence_vma
-sfence_vm   000100000100 . 000 0 1110011 @sfence_vm
 
 # *** 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 bc5263a4e0..4eccdddeaa 100644
--- a/target/riscv/insn_trans/trans_privileged.c.inc
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -127,8 +127,3 @@ static bool trans_sfence_vma(DisasContext *ctx, 
arg_sfence_vma *a)
 #endif
 return false;
 }
-
-static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
-{
-return false;
-}
-- 
2.34.1




[PATCH 6/6] target/riscv: Add support to access ctrsource, ctrtarget, ctrdata regs.

2024-05-29 Thread Rajnesh Kanwal
CTR entries are accessed using ctrsource, ctrtarget and ctrdata
registers using smcsrind/sscsrind extension. This commits extends
the csrind extension to support CTR registers.

ctrsource is accessible through xireg CSR, ctrtarget is accessible
through xireg1 and ctrdata is accessible through xireg2 CSR.

CTR supports maximum depth of 256 entries which are accessed using
xiselect range 0x200 to 0x2ff.

This commits also adds properties to enable CTR extension. CTR can be
enabled using smctr=true and ssctr=true now.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.c |   4 ++
 target/riscv/csr.c | 153 -
 2 files changed, 156 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 30bdfc22ae..a77b1d5caf 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -193,6 +193,8 @@ const RISCVIsaExtData isa_edata_arr[] = {
 ISA_EXT_DATA_ENTRY(sstvala, PRIV_VERSION_1_12_0, has_priv_1_12),
 ISA_EXT_DATA_ENTRY(sstvecd, PRIV_VERSION_1_12_0, has_priv_1_12),
 ISA_EXT_DATA_ENTRY(svade, PRIV_VERSION_1_11_0, ext_svade),
+ISA_EXT_DATA_ENTRY(smctr, PRIV_VERSION_1_12_0, ext_smctr),
+ISA_EXT_DATA_ENTRY(ssctr, PRIV_VERSION_1_12_0, ext_ssctr),
 ISA_EXT_DATA_ENTRY(svadu, PRIV_VERSION_1_12_0, ext_svadu),
 ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval),
 ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot),
@@ -1473,6 +1475,8 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
 MULTI_EXT_CFG_BOOL("sscsrind", ext_sscsrind, false),
 MULTI_EXT_CFG_BOOL("smcdeleg", ext_smcdeleg, false),
 MULTI_EXT_CFG_BOOL("ssccfg", ext_ssccfg, false),
+MULTI_EXT_CFG_BOOL("smctr", ext_smctr, false),
+MULTI_EXT_CFG_BOOL("ssctr", ext_ssctr, false),
 MULTI_EXT_CFG_BOOL("zifencei", ext_zifencei, true),
 MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true),
 MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true),
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 888084d8e5..15b953f268 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -2291,6 +2291,11 @@ static bool xiselect_cd_range(target_ulong isel)
 return (ISELECT_CD_FIRST <= isel && isel <= ISELECT_CD_LAST);
 }
 
+static bool xiselect_ctr_range(target_ulong isel)
+{
+return (CTR_ENTRIES_FIRST <= isel && isel <= CTR_ENTRIES_LAST);
+}
+
 static int rmw_iprio(target_ulong xlen,
  target_ulong iselect, uint8_t *iprio,
  target_ulong *val, target_ulong new_val,
@@ -2336,6 +2341,118 @@ static int rmw_iprio(target_ulong xlen,
 return 0;
 }
 
+static int rmw_xctrsource(CPURISCVState *env, int isel, target_ulong *val,
+  target_ulong new_val, target_ulong wr_mask)
+{
+/*
+ * CTR arrays are treated as circular buffers and TOS always points to next
+ * empty slot, keeping TOS - 1 always pointing to latest entry. Given entry
+ * 0 is always the latest one, traversal is a bit different here. See the
+ * below example.
+ *
+ * Depth = 16.
+ *
+ * idx[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [A] [B] [C] [D] [E] [F]
+ * TOS H
+ * entry   6   5   4   3   2   1   0   F   E   D   C   B   A   9   8   7
+ */
+const uint64_t entry = isel - CTR_ENTRIES_FIRST;
+const uint64_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
+uint64_t idx;
+
+/* Entry greater than depth-1 is read-only zero */
+if (entry >= depth) {
+*val = 0;
+return 0;
+}
+
+idx = get_field(env->sctrstatus, SCTRSTATUS_WRPTR_MASK);
+idx = (idx - entry - 1) & (depth - 1);
+
+if (val) {
+*val = env->ctr_src[idx];
+}
+
+env->ctr_src[idx] = (env->ctr_src[idx] & ~wr_mask) | (new_val & wr_mask);
+
+return 0;
+}
+
+static int rmw_xctrtarget(CPURISCVState *env, int isel, target_ulong *val,
+  target_ulong new_val, target_ulong wr_mask)
+{
+/*
+ * CTR arrays are treated as circular buffers and TOS always points to next
+ * empty slot, keeping TOS - 1 always pointing to latest entry. Given entry
+ * 0 is always the latest one, traversal is a bit different here. See the
+ * below example.
+ *
+ * Depth = 16.
+ *
+ * idx[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [A] [B] [C] [D] [E] [F]
+ * headH
+ * entry   6   5   4   3   2   1   0   F   E   D   C   B   A   9   8   7
+ */
+const uint64_t entry = isel - CTR_ENTRIES_FIRST;
+const uint64_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
+uint64_t idx;
+
+/* Entry greater than depth-1 is read-only zero */
+if (entry >= depth) {
+*val = 0;
+return 0;
+}
+
+idx = get_field(env->sctrstatus, 

[PATCH 0/6] target/riscv: Add support for Control Transfer Records Ext.

2024-05-29 Thread Rajnesh Kanwal
This series enables Control Transfer Records extension support on riscv
platform. This extension is similar to Arch LBR in x86 and BRBE in ARM.
The Extension has been stable and the latest release can be found here [0] 

CTR extension depends on couple of other extensions:

1. S[m|s]csrind : The indirect CSR extension [1] which defines additional
   ([M|S|VS]IREG2-[M|S|VS]IREG6) register to address size limitation of
   RISC-V CSR address space. CTR access ctrsource, ctrtartget and ctrdata
   CSRs using sscsrind extension.

2. Smstateen: The mstateen bit[54] controls the access to the CTR ext to
   S-mode.

3. Sscofpmf: Counter overflow and privilege mode filtering. [2] 

The series is based on Smcdeleg/Ssccfg counter delegation extension [3]
patches. CTR itself doesn't depend on counter delegation support. This
rebase is basically to include the Smcsrind patches.

Due to the dependency of these extensions, the following extensions must be
enabled to use the control transfer records feature.

"smstateen=true,sscofpmf=true,smcsrind=true,sscsrind=true,smctr=true,ssctr=true"
 

Here is the link to a quick guide [5] to setup and run a basic perf demo on
Linux to use CTR Ext.

The Qemu patches can be found here:
https://github.com/rajnesh-kanwal/qemu/tree/ctr_upstream

The opensbi patch can be found here:
https://github.com/rajnesh-kanwal/opensbi/tree/ctr_upstream

The Linux kernel patches can be found here:
https://github.com/rajnesh-kanwal/linux/tree/ctr_upstream

[0]: https://github.com/riscv/riscv-control-transfer-records/release
[1]: https://github.com/riscv/riscv-indirect-csr-access
[2]: https://github.com/riscvarchive/riscv-count-overflow/tree/main
[3]: https://github.com/riscv/riscv-smcdeleg-ssccfg
[4]: https://lore.kernel.org/all/20240217000134.3634191-1-ati...@rivosinc.com/
[5]: 
https://github.com/rajnesh-kanwal/linux/wiki/Running-CTR-basic-demo-on-QEMU-RISC%E2%80%90V-Virt-machine

Rajnesh Kanwal (6):
  target/riscv: Remove obsolete sfence.vm instruction
  target/riscv: Add Control Transfer Records CSR definitions.
  target/riscv: Add support for Control Transfer Records extension CSRs.
  target/riscv: Add support to record CTR entries.
  target/riscv: Add CTR sctrclr instruction.
  target/riscv: Add support to access ctrsource, ctrtarget, ctrdata
regs.

 target/riscv/cpu.c|   4 +
 target/riscv/cpu.h|  14 +
 target/riscv/cpu_bits.h   | 154 +
 target/riscv/cpu_cfg.h|   2 +
 target/riscv/cpu_helper.c | 213 
 target/riscv/csr.c| 312 +-
 target/riscv/helper.h |   8 +-
 target/riscv/insn32.decode|   2 +-
 .../riscv/insn_trans/trans_privileged.c.inc   |  21 +-
 target/riscv/insn_trans/trans_rvi.c.inc   |  27 ++
 target/riscv/op_helper.c  | 117 ++-
 target/riscv/translate.c  |   9 +
 12 files changed, 870 insertions(+), 13 deletions(-)

-- 
2.34.1




[PATCH 3/6] target/riscv: Add support for Control Transfer Records extension CSRs.

2024-05-29 Thread Rajnesh Kanwal
This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
sctrdepth CSRs handling.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.h |   5 ++
 target/riscv/cpu_cfg.h |   2 +
 target/riscv/csr.c | 159 +
 3 files changed, 166 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a185e2d494..3d4d5172b8 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -263,6 +263,11 @@ struct CPUArchState {
 target_ulong mcause;
 target_ulong mtval;  /* since: priv-1.10.0 */
 
+uint64_t mctrctl;
+uint32_t sctrdepth;
+uint32_t sctrstatus;
+uint64_t vsctrctl;
+
 /* Machine and Supervisor interrupt priorities */
 uint8_t miprio[64];
 uint8_t siprio[64];
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index d9354dc80a..d329a65811 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -123,6 +123,8 @@ struct RISCVCPUConfig {
 bool ext_zvfhmin;
 bool ext_smaia;
 bool ext_ssaia;
+bool ext_smctr;
+bool ext_ssctr;
 bool ext_sscofpmf;
 bool ext_smepmp;
 bool rvv_ta_all_1s;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 2f92e4b717..888084d8e5 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -621,6 +621,61 @@ static RISCVException pointer_masking(CPURISCVState *env, 
int csrno)
 return RISCV_EXCP_ILLEGAL_INST;
 }
 
+/*
+ * M-mode:
+ * Without ext_smctr raise illegal inst excep.
+ * Otherwise everything is accessible to m-mode.
+ *
+ * S-mode:
+ * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
+ * Otherwise everything other than mctrctl is accessible.
+ *
+ * VS-mode:
+ * Without ext_ssctr or mstateen.ctr raise illegal inst excep.
+ * Without hstateen.ctr raise virtual illegal inst excep.
+ * Otherwise allow vsctrctl, sctrstatus, 0x200-0x2ff entry range.
+ * Always raise illegal instruction exception for sctrdepth.
+ */
+static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
+{
+/* Check if smctr-ext is present */
+if (riscv_cpu_cfg(env)->ext_smctr) {
+return RISCV_EXCP_NONE;
+}
+
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException ctr_smode(CPURISCVState *env, int csrno)
+{
+if ((env->priv == PRV_M && riscv_cpu_cfg(env)->ext_smctr) ||
+(env->priv == PRV_S && !env->virt_enabled &&
+ riscv_cpu_cfg(env)->ext_ssctr)) {
+return smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
+}
+
+if (env->priv == PRV_S && env->virt_enabled &&
+riscv_cpu_cfg(env)->ext_ssctr) {
+if (csrno == CSR_SCTRSTATUS) {
+return smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
+}
+
+return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+}
+
+return RISCV_EXCP_ILLEGAL_INST;
+}
+
+static RISCVException ctr_vsmode(CPURISCVState *env, int csrno)
+{
+if (env->priv == PRV_S && env->virt_enabled &&
+riscv_cpu_cfg(env)->ext_ssctr) {
+return smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
+}
+
+return ctr_smode(env, csrno);
+}
+
 static RISCVException aia_hmode(CPURISCVState *env, int csrno)
 {
 int ret;
@@ -3835,6 +3890,100 @@ static RISCVException write_satp(CPURISCVState *env, 
int csrno,
 return RISCV_EXCP_NONE;
 }
 
+static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
+target_ulong *ret_val,
+target_ulong new_val, target_ulong wr_mask)
+{
+uint64_t mask = wr_mask & SCTRDEPTH_MASK;
+
+if (ret_val) {
+*ret_val = env->sctrdepth & SCTRDEPTH_MASK;
+}
+
+env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
+
+/* Correct depth. */
+if (wr_mask & SCTRDEPTH_MASK) {
+uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
+
+if (depth > SCTRDEPTH_MAX) {
+env->sctrdepth =
+set_field(env->sctrdepth, SCTRDEPTH_MASK, SCTRDEPTH_MAX);
+}
+
+/* Update sctrstatus.WRPTR with a legal value */
+depth = 16 << depth;
+env->sctrstatus =
+env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
+}
+
+return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_mctrctl(CPURISCVState *env, int csrno,
+target_ulong *ret_val,
+target_ulong new_val, target_ulong wr_mask)
+{
+uint64_t mask = wr_mask & MCTRCTL_MASK;
+
+if (ret_val) {
+*ret_val = env->mctrctl & MCTRCTL_MASK;
+}
+
+env->mctrctl = (env->mctrctl & ~mask) | (new_val & mask);
+
+return RISCV_EXCP_NONE;
+}
+
+static RISCVException rmw_sctrctl(CPURISCVState *env, int csrno,
+target_ulong *ret_val,
+target_ulong new_val,

[PATCH 2/6] target/riscv: Add Control Transfer Records CSR definitions.

2024-05-29 Thread Rajnesh Kanwal
The Control Transfer Records (CTR) extension provides a method to
record a limited branch history in register-accessible internal chip
storage.

This extension is similar to Arch LBR in x86 and BRBE in ARM.
The Extension has been stable and the latest release can be found here
https://github.com/riscv/riscv-control-transfer-records/release

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu_bits.h | 154 
 1 file changed, 154 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 86e15381c8..71ddccaf1a 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -242,6 +242,17 @@
 #define CSR_SIEH0x114
 #define CSR_SIPH0x154
 
+/* Machine-Level Control transfer records CSRs */
+#define CSR_MCTRCTL 0x34e
+
+/* Supervisor-Level Control transfer records CSRs */
+#define CSR_SCTRCTL 0x14e
+#define CSR_SCTRSTATUS  0x14f
+#define CSR_SCTRDEPTH   0x15f
+
+/* VS-Level Control transfer records CSRs */
+#define CSR_VSCTRCTL0x24e
+
 /* Hpervisor CSRs */
 #define CSR_HSTATUS 0x600
 #define CSR_HEDELEG 0x602
@@ -339,6 +350,7 @@
 #define SMSTATEEN0_CS   (1ULL << 0)
 #define SMSTATEEN0_FCSR (1ULL << 1)
 #define SMSTATEEN0_JVT  (1ULL << 2)
+#define SMSTATEEN0_CTR  (1ULL << 54)
 #define SMSTATEEN0_HSCONTXT (1ULL << 57)
 #define SMSTATEEN0_IMSIC(1ULL << 58)
 #define SMSTATEEN0_AIA  (1ULL << 59)
@@ -854,6 +866,148 @@ typedef enum RISCVException {
 #define UMTE_U_PM_INSN  U_PM_INSN
 #define UMTE_MASK (UMTE_U_PM_ENABLE | MMTE_U_PM_CURRENT | UMTE_U_PM_INSN)
 
+/* mctrctl CSR bits. */
+#define MCTRCTL_U_ENABLEBIT(0)
+#define MCTRCTL_S_ENABLEBIT(1)
+#define MCTRCTL_M_ENABLEBIT(2)
+#define MCTRCTL_RASEMU  BIT(7)
+#define MCTRCTL_STE BIT(8)
+#define MCTRCTL_MTE BIT(9)
+#define MCTRCTL_BPFRZ   BIT(11)
+#define MCTRCTL_LCOFIFRZBIT(12)
+#define MCTRCTL_EXCINH  BIT(33)
+#define MCTRCTL_INTRINH BIT(34)
+#define MCTRCTL_TRETINH BIT(35)
+#define MCTRCTL_NTBREN  BIT(36)
+#define MCTRCTL_TKBRINH BIT(37)
+#define MCTRCTL_INDCALL_INH BIT(40)
+#define MCTRCTL_DIRCALL_INH BIT(41)
+#define MCTRCTL_INDJUMP_INH BIT(42)
+#define MCTRCTL_DIRJUMP_INH BIT(43)
+#define MCTRCTL_CORSWAP_INH BIT(44)
+#define MCTRCTL_RET_INH BIT(45)
+#define MCTRCTL_INDOJUMP_INHBIT(46)
+#define MCTRCTL_DIROJUMP_INHBIT(47)
+
+#define MCTRCTL_INH_START   32U
+
+#define MCTRCTL_MASK (MCTRCTL_M_ENABLE | MCTRCTL_S_ENABLE |   \
+  MCTRCTL_U_ENABLE | MCTRCTL_RASEMU | \
+  MCTRCTL_MTE | MCTRCTL_STE | \
+  MCTRCTL_BPFRZ | MCTRCTL_LCOFIFRZ |  \
+  MCTRCTL_EXCINH | MCTRCTL_INTRINH |  \
+  MCTRCTL_TRETINH | MCTRCTL_NTBREN |  \
+  MCTRCTL_TKBRINH | MCTRCTL_INDCALL_INH | \
+  MCTRCTL_DIRCALL_INH | MCTRCTL_INDJUMP_INH | \
+  MCTRCTL_DIRJUMP_INH | MCTRCTL_CORSWAP_INH | \
+  MCTRCTL_RET_INH | MCTRCTL_INDOJUMP_INH |\
+  MCTRCTL_DIROJUMP_INH)
+
+/* sctrctl CSR bits. */
+#define SCTRCTL_U_ENABLE  MCTRCTL_U_ENABLE
+#define SCTRCTL_S_ENABLE  MCTRCTL_S_ENABLE
+#define SCTRCTL_RASEMUMCTRCTL_RASEMU
+#define SCTRCTL_STE   MCTRCTL_STE
+#define SCTRCTL_BPFRZ MCTRCTL_BPFRZ
+#define SCTRCTL_LCOFIFRZ  MCTRCTL_LCOFIFRZ
+#define SCTRCTL_EXCINHMCTRCTL_EXCINH
+#define SCTRCTL_INTRINH   MCTRCTL_INTRINH
+#define SCTRCTL_TRETINH   MCTRCTL_TRETINH
+#define SCTRCTL_NTBRENMCTRCTL_NTBREN
+#define SCTRCTL_TKBRINH   MCTRCTL_TKBRINH
+#define SCTRCTL_INDCALL_INH   MCTRCTL_INDCALL_INH
+#define SCTRCTL_DIRCALL_INH   MCTRCTL_DIRCALL_INH
+#define SCTRCTL_INDJUMP_INH   MCTRCTL_INDJUMP_INH
+#define SCTRCTL_DIRJUMP_INH   MCTRCTL_DIRJUMP_INH
+#define SCTRCTL_CORSWAP_INH   MCTRCTL_CORSWAP_INH
+#define SCTRCTL_RET_INH   MCTRCTL_RET_INH
+#define SCTRCTL_INDOJUMP_INH  MCTRCTL_INDOJUMP_INH
+#define SCTRCTL_DIROJUMP_INH  MCTRCTL_DIROJUMP_INH
+
+#define SCTRCTL_MASK (SCTRCTL_S_ENABLE | SCTRCTL_U_ENABLE |   \
+  SCTRCTL_RASEMU | SCTRCTL_STE |  \
+  SCTRCTL_BPFRZ | SCTRCTL_LCOFIFRZ |  \
+  SCTRCTL_EXCINH | SCTRCTL_INTRINH |  \
+  SCTRCTL_TRETINH | SCTRCTL_NTBREN |  \
+  SCTRCTL_TKBRINH | SCTRCTL_INDCALL_INH | \
+  SCTRCTL_DIRCALL_INH | SCTRCTL_INDJUMP_INH | \
+  SCTRCTL_DIRJUMP_INH | SCTRCTL_CORSWAP_INH | \
+  SCTRCTL_RET_INH | SCTRCTL_INDOJUMP_INH |\
+

[PATCH 5/6] target/riscv: Add CTR sctrclr instruction.

2024-05-29 Thread Rajnesh Kanwal
CTR extension adds a new instruction sctrclr to quickly
clear the recorded entries buffer.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.h |  1 +
 target/riscv/cpu_helper.c  |  7 +++
 target/riscv/insn32.decode |  1 +
 target/riscv/insn_trans/trans_privileged.c.inc | 10 ++
 target/riscv/op_helper.c   |  5 +
 5 files changed, 24 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a294a5372a..fade71aa09 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -572,6 +572,7 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong 
newpriv, bool virt_en);
 void riscv_ctr_freeze(CPURISCVState *env, uint64_t freeze_mask);
 void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
  uint64_t type, target_ulong prev_priv, bool 
prev_virt);
+void riscv_ctr_clear(CPURISCVState *env);
 
 void riscv_translate_init(void);
 G_NORETURN void riscv_raise_exception(CPURISCVState *env,
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index e064a7306e..45502f50a7 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -704,6 +704,13 @@ void riscv_ctr_freeze(CPURISCVState *env, uint64_t 
freeze_mask)
 }
 }
 
+void riscv_ctr_clear(CPURISCVState *env)
+{
+memset(env->ctr_src, 0x0, sizeof(env->ctr_src));
+memset(env->ctr_dst, 0x0, sizeof(env->ctr_dst));
+memset(env->ctr_data, 0x0, sizeof(env->ctr_data));
+}
+
 static uint64_t riscv_ctr_priv_to_mask(target_ulong priv, bool virt)
 {
 switch (priv) {
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 9cb1a1b4ec..d3d38c7c68 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -107,6 +107,7 @@
 # *** Privileged Instructions ***
 ecall    0 000 0 1110011
 ebreak  0001 0 000 0 1110011
+sctrclr 00010100 0 000 0 1110011
 uret00000010 0 000 0 1110011
 sret000100000010 0 000 0 1110011
 mret001100000010 0 000 0 1110011
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc 
b/target/riscv/insn_trans/trans_privileged.c.inc
index 339d659151..dd9da8651f 100644
--- a/target/riscv/insn_trans/trans_privileged.c.inc
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -69,6 +69,16 @@ static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a)
 return true;
 }
 
+static bool trans_sctrclr(DisasContext *ctx, arg_sctrclr *a)
+{
+#ifndef CONFIG_USER_ONLY
+gen_helper_ctr_clear(tcg_env);
+return true;
+#else
+return false;
+#endif
+}
+
 static bool trans_uret(DisasContext *ctx, arg_uret *a)
 {
 return false;
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index c8053d9c2f..89423c04b3 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -461,6 +461,11 @@ void helper_ctr_branch(CPURISCVState *env, target_ulong 
src, target_ulong dest,
 }
 }
 
+void helper_ctr_clear(CPURISCVState *env)
+{
+riscv_ctr_clear(env);
+}
+
 void helper_wfi(CPURISCVState *env)
 {
 CPUState *cs = env_cpu(env);
-- 
2.34.1




[PATCH 4/6] target/riscv: Add support to record CTR entries.

2024-05-29 Thread Rajnesh Kanwal
This commit adds logic to records CTR entries of different types
and adds required hooks in TCG and interrupt/Exception logic to
record events.

This commit also adds support to invoke freeze CTR logic for breakpoint
exceptions and counter overflow interrupts.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.h|   8 +
 target/riscv/cpu_helper.c | 206 ++
 target/riscv/helper.h |   8 +-
 .../riscv/insn_trans/trans_privileged.c.inc   |   6 +-
 target/riscv/insn_trans/trans_rvi.c.inc   |  27 +++
 target/riscv/op_helper.c  | 112 +-
 target/riscv/translate.c  |   9 +
 7 files changed, 370 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 3d4d5172b8..a294a5372a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -268,6 +268,10 @@ struct CPUArchState {
 uint32_t sctrstatus;
 uint64_t vsctrctl;
 
+uint64_t ctr_src[16 << SCTRDEPTH_MAX];
+uint64_t ctr_dst[16 << SCTRDEPTH_MAX];
+uint64_t ctr_data[16 << SCTRDEPTH_MAX];
+
 /* Machine and Supervisor interrupt priorities */
 uint8_t miprio[64];
 uint8_t siprio[64];
@@ -565,6 +569,10 @@ RISCVException smstateen_acc_ok(CPURISCVState *env, int 
index, uint64_t bit);
 #endif
 void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool 
virt_en);
 
+void riscv_ctr_freeze(CPURISCVState *env, uint64_t freeze_mask);
+void riscv_ctr_add_entry(CPURISCVState *env, target_long src, target_long dst,
+ uint64_t type, target_ulong prev_priv, bool 
prev_virt);
+
 void riscv_translate_init(void);
 G_NORETURN void riscv_raise_exception(CPURISCVState *env,
   uint32_t exception, uintptr_t pc);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index a441a03ef4..e064a7306e 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -663,6 +663,10 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t 
mask, uint64_t value)
 
 BQL_LOCK_GUARD();
 
+if (MIP_LCOFIP & value & mask) {
+riscv_ctr_freeze(env, MCTRCTL_LCOFIFRZ);
+}
+
 env->mip = (env->mip & ~mask) | (value & mask);
 
 riscv_cpu_interrupt(env);
@@ -691,6 +695,197 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, 
uint32_t priv,
 }
 }
 
+void riscv_ctr_freeze(CPURISCVState *env, uint64_t freeze_mask)
+{
+assert((freeze_mask & (~(MCTRCTL_BPFRZ | MCTRCTL_LCOFIFRZ))) == 0);
+
+if (env->mctrctl & freeze_mask) {
+env->sctrstatus |= SCTRSTATUS_FROZEN;
+}
+}
+
+static uint64_t riscv_ctr_priv_to_mask(target_ulong priv, bool virt)
+{
+switch (priv) {
+case PRV_M:
+return MCTRCTL_M_ENABLE;
+case PRV_S:
+if (virt) {
+return VSCTRCTL_VS_ENABLE;
+}
+return MCTRCTL_S_ENABLE;
+case PRV_U:
+if (virt) {
+return VSCTRCTL_VU_ENABLE;
+}
+return MCTRCTL_U_ENABLE;
+}
+
+g_assert_not_reached();
+}
+
+static uint64_t riscv_ctr_get_control(CPURISCVState *env, target_long priv,
+  bool virt)
+{
+switch (priv) {
+case PRV_M:
+return env->mctrctl;
+case PRV_S:
+case PRV_U:
+if (virt) {
+return env->vsctrctl;
+}
+return env->mctrctl;
+}
+
+g_assert_not_reached();
+}
+
+/*
+ * Special cases for traps and trap returns:
+ *
+ * 1- Traps, and trap returns, between enabled modes are recorded as normal.
+ * 2- Traps from an inhibited mode to an enabled mode, and trap returns from an
+ * enabled mode back to an inhibited mode, are partially recorded.  In such
+ * cases, the PC from the inhibited mode (source PC for traps, and target PC
+ * for trap returns) is 0.
+ *
+ * 3- Trap returns from an inhibited mode to an enabled mode are not recorded.
+ * Traps from an enabled mode to an inhibited mode, known as external traps,
+ * receive special handling.
+ * By default external traps are not recorded, but a handshake mechanism exists
+ * to allow partial recording.  Software running in the target mode of the trap
+ * can opt-in to allowing CTR to record traps into that mode even when the mode
+ * is inhibited.  The MTE, STE, and VSTE bits allow M-mode, S-mode, and 
VS-mode,
+ * respectively, to opt-in. When an External Trap occurs, and xTE=1, such that
+ * x is the target privilege mode of the trap, will CTR record the trap. In 
such
+ * cases, the target PC is 0.
+ */
+/*
+ * CTR arrays are implemented as circular buffers and new entry is stored at
+ * sctrstatus.WRPTR, but they are presented to software as moving circular
+ * buffers. Which means, software get's the illusion that whenever a new entry
+ * is added the whole buffer is moved by one place and the new entry is added 
at
+ * the start keeping new entry at idx

[PATCH v2 0/2] target/riscv: Minor fixes and improvements for Virtual IRQs

2024-05-20 Thread Rajnesh Kanwal
This series contains few miscellaneous fixes related to Virtual IRQs
and related code. The first patch changes CSR mask widths to 64bit
as AIA introduces half CSRs in case of 32bit systems.

Second patch fixes guest and core local IRQ overlap. Qemu creates
a single IRQ range which is shared between core local interrupts
and guests in riscv_cpu_init(). Even though, in the current state
there is no device generating interrupts in the 13:63 range, and
virtual IRQ logic in Qemu also doesn't go through riscv_cpu_set_irq()
path, it's better to keep local and guest range separate to avoid
confusion and any future issues.

Patches can be found here on github [0] and v1 of the series
can be found here [1].

Patches are based on alistair/riscv-to-apply.next.

[0] https://github.com/rajnesh-kanwal/qemu/tree/dev/rkanwal/irq_fixes_v2
[1] https://lore.kernel.org/all/20240513114602.72098-1-rkan...@rivosinc.com/

Changes from v1->v2:
1. Check patch fixes.
2. Removed commit title split from Fixes tags.

Rajnesh Kanwal (2):
  target/riscv: Extend virtual irq csrs masks to be 64 bit wide.
  target/riscv: Move Guest irqs out of the core local irqs range.

 target/riscv/cpu_bits.h |  3 ++-
 target/riscv/csr.c  | 23 +++
 2 files changed, 17 insertions(+), 9 deletions(-)

-- 
2.34.1




[PATCH v2 1/2] target/riscv: Extend virtual irq csrs masks to be 64 bit wide.

2024-05-20 Thread Rajnesh Kanwal
AIA extends the width of all IRQ CSRs to 64bit even
in 32bit systems by adding missing half CSRs.

This seems to be missed while adding support for
virtual IRQs. The whole logic seems to be correct
except the width of the masks.

Fixes: 1697837ed9 ("target/riscv: Add M-mode virtual interrupt and IRQ 
filtering support.")
Fixes: 40336d5b1d ("target/riscv: Add HS-mode virtual interrupt and IRQ 
filtering support.")

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Daniel Henrique Barboza 
---
 target/riscv/csr.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 6b460ee0e8..152796ebc0 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1200,18 +1200,18 @@ static const target_ulong sstatus_v1_10_mask = 
SSTATUS_SIE | SSTATUS_SPIE |
  */
 
 /* Bit STIP can be an alias of mip.STIP that's why it's writable in mvip. */
-static const target_ulong mvip_writable_mask = MIP_SSIP | MIP_STIP | MIP_SEIP |
+static const uint64_t mvip_writable_mask = MIP_SSIP | MIP_STIP | MIP_SEIP |
 LOCAL_INTERRUPTS;
-static const target_ulong mvien_writable_mask = MIP_SSIP | MIP_SEIP |
+static const uint64_t mvien_writable_mask = MIP_SSIP | MIP_SEIP |
 LOCAL_INTERRUPTS;
 
-static const target_ulong sip_writable_mask = SIP_SSIP | LOCAL_INTERRUPTS;
-static const target_ulong hip_writable_mask = MIP_VSSIP;
-static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP |
+static const uint64_t sip_writable_mask = SIP_SSIP | LOCAL_INTERRUPTS;
+static const uint64_t hip_writable_mask = MIP_VSSIP;
+static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP |
 MIP_VSEIP | LOCAL_INTERRUPTS;
-static const target_ulong hvien_writable_mask = LOCAL_INTERRUPTS;
+static const uint64_t hvien_writable_mask = LOCAL_INTERRUPTS;
 
-static const target_ulong vsip_writable_mask = MIP_VSSIP | LOCAL_INTERRUPTS;
+static const uint64_t vsip_writable_mask = MIP_VSSIP | LOCAL_INTERRUPTS;
 
 const bool valid_vm_1_10_32[16] = {
 [VM_1_10_MBARE] = true,
-- 
2.34.1




[PATCH v2 2/2] target/riscv: Move Guest irqs out of the core local irqs range.

2024-05-20 Thread Rajnesh Kanwal
Qemu maps IRQs 0:15 for core interrupts and 16 onward for
guest interrupts which are later translated to hgiep in
`riscv_cpu_set_irq()` function.

With virtual IRQ support added, software now can fully
use the whole local interrupt range without any actual
hardware attached.

This change moves the guest interrupt range after the
core local interrupt range to avoid clash.

Fixes: 1697837ed9 ("target/riscv: Add M-mode virtual interrupt and IRQ 
filtering support.")
Fixes: 40336d5b1d ("target/riscv: Add HS-mode virtual interrupt and IRQ 
filtering support.")

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu_bits.h | 3 ++-
 target/riscv/csr.c  | 9 -
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 74318a925c..a470fda9be 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -695,7 +695,8 @@ typedef enum RISCVException {
 #define IRQ_M_EXT  11
 #define IRQ_S_GEXT 12
 #define IRQ_PMU_OVF13
-#define IRQ_LOCAL_MAX  16
+#define IRQ_LOCAL_MAX  64
+/* -1 is due to bit zero of hgeip and hgeie being ROZ. */
 #define IRQ_LOCAL_GUEST_MAX(TARGET_LONG_BITS - 1)
 
 /* mip masks */
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 152796ebc0..464e0e57a3 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1148,7 +1148,14 @@ static RISCVException write_stimecmph(CPURISCVState 
*env, int csrno,
 
 #define VSTOPI_NUM_SRCS 5
 
-#define LOCAL_INTERRUPTS (~0x1FFF)
+/*
+ * All core local interrupts except the fixed ones 0:12. This macro is for
+ * virtual interrupts logic so please don't change this to avoid messing up
+ * the whole support, For reference see AIA spec: `5.3 Interrupt filtering and
+ * virtual interrupts for supervisor level` and `6.3.2 Virtual interrupts for
+ * VS level`.
+ */
+#define LOCAL_INTERRUPTS   (~0x1FFFULL)
 
 static const uint64_t delegable_ints =
 S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS | MIP_LCOFIP;
-- 
2.34.1




[PATCH 1/2] target/riscv: Extend virtual irq csrs masks to be 64 bit wide.

2024-05-13 Thread Rajnesh Kanwal
AIA extends the width of all IRQ CSRs to 64bit even
in 32bit systems by adding missing half CSRs.

This seems to be missed while adding support for
virtual IRQs. The whole logic seems to be correct
except the width of the masks.

Fixes: 1697837ed9 ("target/riscv: Add M-mode virtual
interrupt and IRQ filtering support.")
Fixes: 40336d5b1d ("target/riscv: Add HS-mode virtual
interrupt and IRQ filtering support.")

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/csr.c | 14 +++---
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 45b548eb0b..c9d685dcc5 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1193,18 +1193,18 @@ static const target_ulong sstatus_v1_10_mask = 
SSTATUS_SIE | SSTATUS_SPIE |
  */
 
 /* Bit STIP can be an alias of mip.STIP that's why it's writable in mvip. */
-static const target_ulong mvip_writable_mask = MIP_SSIP | MIP_STIP | MIP_SEIP |
+static const uint64_t mvip_writable_mask = MIP_SSIP | MIP_STIP | MIP_SEIP |
 LOCAL_INTERRUPTS;
-static const target_ulong mvien_writable_mask = MIP_SSIP | MIP_SEIP |
+static const uint64_t mvien_writable_mask = MIP_SSIP | MIP_SEIP |
 LOCAL_INTERRUPTS;
 
-static const target_ulong sip_writable_mask = SIP_SSIP | LOCAL_INTERRUPTS;
-static const target_ulong hip_writable_mask = MIP_VSSIP;
-static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP |
+static const uint64_t sip_writable_mask = SIP_SSIP | LOCAL_INTERRUPTS;
+static const uint64_t hip_writable_mask = MIP_VSSIP;
+static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP |
 MIP_VSEIP | LOCAL_INTERRUPTS;
-static const target_ulong hvien_writable_mask = LOCAL_INTERRUPTS;
+static const uint64_t hvien_writable_mask = LOCAL_INTERRUPTS;
 
-static const target_ulong vsip_writable_mask = MIP_VSSIP | LOCAL_INTERRUPTS;
+static const uint64_t vsip_writable_mask = MIP_VSSIP | LOCAL_INTERRUPTS;
 
 const bool valid_vm_1_10_32[16] = {
 [VM_1_10_MBARE] = true,
-- 
2.34.1




[PATCH 2/2] target/riscv: Move Guest irqs out of the core local irqs range.

2024-05-13 Thread Rajnesh Kanwal
Qemu maps IRQs 0:15 for core interrupts and 16 onward for
guest interrupts which are later translated to hgiep in
`riscv_cpu_set_irq()` function.

With virtual IRQ support added, software now can fully
use the whole local interrupt range without any actual
hardware attached.

This change moves the guest interrupt range after the
core local interrupt range to avoid clash.

Fixes: 1697837ed9 ("target/riscv: Add M-mode virtual
interrupt and IRQ filtering support.")
Fixes: 40336d5b1d ("target/riscv: Add HS-mode virtual
interrupt and IRQ filtering support.")

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu_bits.h | 3 ++-
 target/riscv/csr.c  | 7 ++-
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 13ce2218d1..33f28bb115 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -664,7 +664,8 @@ typedef enum RISCVException {
 #define IRQ_M_EXT  11
 #define IRQ_S_GEXT 12
 #define IRQ_PMU_OVF13
-#define IRQ_LOCAL_MAX  16
+#define IRQ_LOCAL_MAX  64
+/* -1 is due to bit zero of hgeip and hgeie being ROZ. */
 #define IRQ_LOCAL_GUEST_MAX(TARGET_LONG_BITS - 1)
 
 /* mip masks */
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index c9d685dcc5..78f42fcae5 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1141,7 +1141,12 @@ static RISCVException write_stimecmph(CPURISCVState 
*env, int csrno,
 
 #define VSTOPI_NUM_SRCS 5
 
-#define LOCAL_INTERRUPTS (~0x1FFF)
+/* All core local interrupts except the fixed ones 0:12. This macro is for 
virtual
+ * interrupts logic so please don't change this to avoid messing up the whole 
support,
+ * For reference see AIA spec: `5.3 Interrupt filtering and virtual interrupts 
for
+ * supervisor level` and `6.3.2 Virtual interrupts for VS level`.
+ */
+#define LOCAL_INTERRUPTS   (~0x1FFFULL)
 
 static const uint64_t delegable_ints =
 S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS | MIP_LCOFIP;
-- 
2.34.1




[PATCH 0/2] Minor fixes and improvements for Virtual IRQs

2024-05-13 Thread Rajnesh Kanwal
This series contains few miscellaneous fixes related to Virtual IRQs
and related code. The first patch changes CSR mask widths to 64bit
as AIA introduces half CSRs in case of 32bit systems.

Second patch fixes guest and core local IRQ overlap. Qemu creates
a single IRQ range which is shared between core local interrupts
and guests in riscv_cpu_init(). Even though, in the current state
there is no device generating interrupts in the 13:63 range, and
virtual IRQ logic in Qemu also doesn't go through riscv_cpu_set_irq()
path, it's better to keep local and guest range separate to avoid
confusion and any future issues.

Patches can be found here on github:
https://github.com/rajnesh-kanwal/qemu/tree/dev/rkanwal/irq_fixes

Signed-off-by: Rajnesh Kanwal 
---
Rajnesh Kanwal (2):
  target/riscv: Extend virtual irq csrs masks to be 64 bit wide.
  target/riscv: Move Guest irqs out of the core local irqs range.

 target/riscv/cpu_bits.h |  3 ++-
 target/riscv/csr.c  | 21 +
 2 files changed, 15 insertions(+), 9 deletions(-)
---
base-commit: 09d8c49f23e9a130593984d5c8cf048bdd76f73e
-- 
Regards,
Rajnesh Kanwal



[PATCH v5 1/6] target/riscv: Without H-mode mask all HS mode inturrupts in mie.

2023-10-16 Thread Rajnesh Kanwal
Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/csr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 30cc21e979..4847b47a98 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1525,7 +1525,7 @@ static RISCVException rmw_mie64(CPURISCVState *env, int 
csrno,
 env->mie = (env->mie & ~mask) | (new_val & mask);
 
 if (!riscv_has_ext(env, RVH)) {
-env->mie &= ~((uint64_t)MIP_SGEIP);
+env->mie &= ~((uint64_t)HS_MODE_INTERRUPTS);
 }
 
 return RISCV_EXCP_NONE;
-- 
2.34.1




[PATCH v5 5/6] target/riscv: Add M-mode virtual interrupt and IRQ filtering support.

2023-10-16 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from M-mode
into S-mode using mvien and mvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M-mode to assert virtual interrupts to S-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0/riscv-interrupts-1.0.pdf

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Daniel Henrique Barboza 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|   8 ++
 target/riscv/cpu_bits.h   |   6 +
 target/riscv/cpu_helper.c |  26 +++-
 target/riscv/csr.c| 279 ++
 target/riscv/machine.c|   7 +-
 6 files changed, 291 insertions(+), 38 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index efafc0ba0b..859ac59c6c 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -813,7 +813,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * Definition of the WFI instruction requires it to ignore the privilege
  * mode and delegation registers, but respect individual enables
  */
-return riscv_cpu_all_pending(env) != 0;
+return riscv_cpu_all_pending(env) != 0 ||
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6fe32e6b38..30f9481f45 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -202,6 +202,12 @@ struct CPUArchState {
 uint64_t mie;
 uint64_t mideleg;
 
+/*
+ * When mideleg[i]=0 and mvien[i]=1, sie[i] is no more
+ * alias of mie[i] and needs to be maintained separatly.
+ */
+uint64_t sie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -222,6 +228,8 @@ struct CPUArchState {
 /* AIA CSRs */
 target_ulong miselect;
 target_ulong siselect;
+uint64_t mvien;
+uint64_t mvip;
 
 /* Hypervisor CSRs */
 target_ulong hstatus;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 3d6ffaabc7..ebd7917d49 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -735,6 +735,12 @@ typedef enum RISCVException {
 #define MIE_SSIE   (1 << IRQ_S_SOFT)
 #define MIE_USIE   (1 << IRQ_U_SOFT)
 
+/* Machine constants */
+#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
+#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
+#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
+#define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS))
+
 /* General PointerMasking CSR bits */
 #define PM_ENABLE   0x0001ULL
 #define PM_CURRENT  0x0002ULL
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 581b8c6380..b36161708a 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -376,6 +376,10 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 return best_irq;
 }
 
+/*
+ * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
+ * are returned in riscv_cpu_sirq_pending().
+ */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
 uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -398,9 +402,10 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 {
 uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
 ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs_f = env->mvip & env->mvien & ~env->mideleg & env->sie;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs, env->siprio);
+irqs | irqs_f, env->siprio);
 }
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
@@ -414,8 +419,8 @@ int riscv_cpu_vsirq_pending(CPURISCVState *env)
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
 int virq;
-uint64_t irqs, pending, mie, hsie, vsie;
 
 /* Determine interrupt enable state of all privilege modes */
 if (env->virt_enabled) {
@@ -441,8 +446,11 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->miprio);
 }
 
+/* Check for virtual S-mode interrupts. */
+irqs_f = env->mvip & (env->mvien & ~env->mideleg) & env->sie;
+
 /* Check HS-mode interrupts */
-irqs = pending & env->mideleg & ~en

[PATCH v5 4/6] target/riscv: Split interrupt logic from riscv_cpu_update_mip.

2023-10-16 Thread Rajnesh Kanwal
This is to allow virtual interrupts to be inserted into S and VS
modes. Given virtual interrupts will be maintained in separate
mvip and hvip CSRs, riscv_cpu_update_mip will no longer be in the
path and interrupts need to be triggered for these cases from
rmw_hvip64 and rmw_mvip64 functions.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu.h|  1 +
 target/riscv/cpu_helper.c | 25 ++---
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index f8ffa5ee38..6fe32e6b38 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -463,6 +463,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_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 *),
  void *arg);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index aaeb1d0d5c..581b8c6380 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -620,11 +620,12 @@ 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_interrupt(CPURISCVState *env)
 {
+uint64_t gein, vsgein = 0, vstip = 0;
 CPUState *cs = env_cpu(env);
-uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
+
+QEMU_IOTHREAD_LOCK_GUARD();
 
 if (env->virt_enabled) {
 gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -633,15 +634,25 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, 
uint64_t mask,
 
 vstip = env->vstime_irq ? MIP_VSTIP : 0;
 
-QEMU_IOTHREAD_LOCK_GUARD();
-
-env->mip = (env->mip & ~mask) | (value & mask);
-
 if (env->mip | vsgein | vstip) {
 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
+}
+
+uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t 
value)
+{
+uint64_t old = env->mip;
+
+/* No need to update mip for VSTIP */
+mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
+
+QEMU_IOTHREAD_LOCK_GUARD();
+
+env->mip = (env->mip & ~mask) | (value & mask);
+
+riscv_cpu_interrupt(env);
 
 return old;
 }
-- 
2.34.1




[PATCH v5 3/6] target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled

2023-10-16 Thread Rajnesh Kanwal
With H-Ext supported, VS bits are all hardwired to one in MIDELEG
denoting always delegated interrupts. This is being done in rmw_mideleg
but given mideleg is used in other places when routing interrupts
this change initializes it in riscv_cpu_realize to be on the safe side.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/tcg/tcg-cpu.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 418b040d6d..bbce254ee1 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -618,7 +618,12 @@ static bool tcg_cpu_realize(CPUState *cs, Error **errp)
 cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
   riscv_pmu_timer_cb, cpu);
 }
- }
+}
+
+/* With H-Ext, VSSIP, VSTIP, VSEIP and SGEIP are hardwired to one. */
+if (riscv_has_ext(env, RVH)) {
+env->mideleg = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP | MIP_SGEIP;
+}
 #endif
 
 return true;
-- 
2.34.1




[PATCH v5 6/6] target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

2023-10-16 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from HS-mode
into VS-mode using hvien and hvip csrs. This also allows for IRQ filtering
from HS-mode.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows HS-mode to assert virtual interrupts to VS-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "6.3.2 Virtual
interrupts for VS level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0/riscv-interrupts-1.0.pdf

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Daniel Henrique Barboza 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|  14 +++
 target/riscv/cpu_helper.c |  48 +++---
 target/riscv/csr.c| 196 ++
 target/riscv/machine.c|   7 +-
 5 files changed, 236 insertions(+), 32 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 859ac59c6c..2f98ce56e0 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -814,7 +814,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * mode and delegation registers, but respect individual enables
  */
 return riscv_cpu_all_pending(env) != 0 ||
-riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE ||
+riscv_cpu_vsirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 30f9481f45..7f61e17202 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -208,6 +208,12 @@ struct CPUArchState {
  */
 uint64_t sie;
 
+/*
+ * When hideleg[i]=0 and hvien[i]=1, vsie[i] is no more
+ * alias of sie[i] (mie[i]) and needs to be maintained separatly.
+ */
+uint64_t vsie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -242,6 +248,14 @@ struct CPUArchState {
 target_ulong hgeie;
 target_ulong hgeip;
 uint64_t htimedelta;
+uint64_t hvien;
+
+/*
+ * Bits VSSIP, VSTIP and VSEIP in hvip are maintained in mip. Other bits
+ * from 0:12 are reserved. Bits 13:63 are not aliased and must be 
separately
+ * maintain in hvip.
+ */
+uint64_t hvip;
 
 /* Hypervisor controlled virtual interrupt priorities */
 target_ulong hvictl;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index b36161708a..b7af69de53 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -377,8 +377,9 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 }
 
 /*
- * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
- * are returned in riscv_cpu_sirq_pending().
+ * Doesn't report interrupts inserted using mvip from M-mode firmware or
+ * using hvip bits 13:63 from HS-mode. Those are returned in
+ * riscv_cpu_sirq_pending() and riscv_cpu_vsirq_pending().
  */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
@@ -410,16 +411,23 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
 {
-uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
-(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg & env->hideleg;
+uint64_t irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+uint64_t vsbits;
+
+/* Bring VS-level bits to correct position */
+vsbits = irqs & VS_MODE_INTERRUPTS;
+irqs &= ~VS_MODE_INTERRUPTS;
+irqs |= vsbits >> 1;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs >> 1, env->hviprio);
+(irqs | irqs_f_vs), env->hviprio);
 }
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
-uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f, irqs_f_vs;
+uint64_t vsbits, irq_delegated;
 int virq;
 
 /* Determine interrupt enable state of all privilege modes */
@@ -456,12 +464,26 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->siprio);
 }
 
+/* Check for virtual VS-mode interrupts. */
+irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+
 /* Check VS-mode interrupts */
-irqs = pending & env->mideleg & env->hideleg & -vsie;
+irq_delegated = pending & env->mideleg & env->hideleg;
+
+/* Bring VS-level bits to correct position */
+vsbits = irq_delegated & VS_MODE_INTERRUPTS;
+irq_delegated &= ~VS_MODE_INTERRUPTS;
+irq_delegated |= vsbits >> 1;
+
+irqs = (irq_delegated | irqs_f_vs) & -vsie;
 if (irqs) {
 virq = riscv_cp

[PATCH v5 0/6] target/riscv: Add RISC-V Virtual IRQs and IRQ filtering support

2023-10-16 Thread Rajnesh Kanwal
This series adds M and HS-mode virtual interrupt and IRQ filtering support.
This allows inserting virtual interrupts from M/HS-mode into S/VS-mode
using mvien/hvien and mvip/hvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M/HS-mode to assert virtual interrupts to
S/VS-mode that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level" and "6.3.2 Virtual
interrupts for VS level".

Most of the testing is done by hacking around OpenSBI and linux host.
The changes for those can be found at [1] and [2].

It's my first touch on RISC-V qemu IRQ subsystem. Any feedback would
be much appreciated.

The change can also be found on github [3].

TODO: This change doesn't support delegating virtual interrupts injected
by M-mode to VS-mode by the Hypervisor. This is true for bits 13:63 only.

Thanks
Rajnesh

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0/riscv-interrupts-1.0.pdf
[1]: https://github.com/rajnesh-kanwal/opensbi/tree/dev/rkanwal/irq_filter
[2]: https://github.com/rajnesh-kanwal/linux/commits/dev/rkanwal/aia_irq_filter
[3]: https://github.com/rajnesh-kanwal/qemu/tree/dev/rkanwal/riscv_irq_filter

v5:
 * Rebased the patches onto alister/riscv-to-apply.next again. Updated
   version_id and minimum_version_id in vmstate_riscv_cpu and
   vmstate_hyper. Also updated AIA spec links.

v4:
 * Rebased the patches onto alister/riscv-to-apply.next. There were
   some rebasing conflicts due to code restructuring.

v3:
 * Rebased the patches and added reviewed-by tags.

v2:
 * Move RISCV_EXCP_SEMIHOST to switch case and remove special handling.
 * Fix linux-user build.

Rajnesh Kanwal (6):
  target/riscv: Without H-mode mask all HS mode inturrupts in mie.
  target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.
  target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled
  target/riscv: Split interrupt logic from riscv_cpu_update_mip.
  target/riscv: Add M-mode virtual interrupt and IRQ filtering support.
  target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

 target/riscv/cpu.c |   4 +-
 target/riscv/cpu.h |  23 ++
 target/riscv/cpu_bits.h|   6 +
 target/riscv/cpu_helper.c  |  99 ++--
 target/riscv/csr.c | 477 +
 target/riscv/machine.c |  14 +-
 target/riscv/tcg/tcg-cpu.c |   7 +-
 7 files changed, 551 insertions(+), 79 deletions(-)

-- 
2.34.1




[PATCH v5 2/6] target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.

2023-10-16 Thread Rajnesh Kanwal
RISCV_EXCP_SEMIHOST is set to 0x10, which can be a local interrupt id
as well. This change moves RISCV_EXCP_SEMIHOST to switch case so that
async flag check is performed before invoking semihosting logic.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu_helper.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 8c28241c18..aaeb1d0d5c 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1605,15 +1605,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 target_ulong htval = 0;
 target_ulong mtval2 = 0;
 
-if  (cause == RISCV_EXCP_SEMIHOST) {
-do_common_semihosting(cs);
-env->pc += 4;
-return;
-}
-
 if (!async) {
 /* set tval to badaddr for traps with address information */
 switch (cause) {
+case RISCV_EXCP_SEMIHOST:
+do_common_semihosting(cs);
+env->pc += 4;
+return;
 case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
 case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
 case RISCV_EXCP_LOAD_ADDR_MIS:
-- 
2.34.1




[PATCH v4 3/6] target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled

2023-10-12 Thread Rajnesh Kanwal
With H-Ext supported, VS bits are all hardwired to one in MIDELEG
denoting always delegated interrupts. This is being done in rmw_mideleg
but given mideleg is used in other places when routing interrupts
this change initializes it in riscv_cpu_realize to be on the safe side.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/tcg/tcg-cpu.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index a28918ab30..34e034b9f3 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -618,7 +618,12 @@ static bool tcg_cpu_realize(CPUState *cs, Error **errp)
 cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
   riscv_pmu_timer_cb, cpu);
 }
- }
+}
+
+/* With H-Ext, VSSIP, VSTIP, VSEIP and SGEIP are hardwired to one. */
+if (riscv_has_ext(env, RVH)) {
+env->mideleg = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP | MIP_SGEIP;
+}
 #endif
 
 return true;
-- 
2.34.1




[PATCH v4 5/6] target/riscv: Add M-mode virtual interrupt and IRQ filtering support.

2023-10-12 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from M-mode
into S-mode using mvien and mvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M-mode to assert virtual interrupts to S-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Daniel Henrique Barboza 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|   8 ++
 target/riscv/cpu_bits.h   |   6 +
 target/riscv/cpu_helper.c |  26 +++-
 target/riscv/csr.c| 279 ++
 target/riscv/machine.c|   3 +
 6 files changed, 289 insertions(+), 36 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ac4a6c7eec..6546634f9d 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -813,7 +813,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * Definition of the WFI instruction requires it to ignore the privilege
  * mode and delegation registers, but respect individual enables
  */
-return riscv_cpu_all_pending(env) != 0;
+return riscv_cpu_all_pending(env) != 0 ||
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6fe32e6b38..30f9481f45 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -202,6 +202,12 @@ struct CPUArchState {
 uint64_t mie;
 uint64_t mideleg;
 
+/*
+ * When mideleg[i]=0 and mvien[i]=1, sie[i] is no more
+ * alias of mie[i] and needs to be maintained separatly.
+ */
+uint64_t sie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -222,6 +228,8 @@ struct CPUArchState {
 /* AIA CSRs */
 target_ulong miselect;
 target_ulong siselect;
+uint64_t mvien;
+uint64_t mvip;
 
 /* Hypervisor CSRs */
 target_ulong hstatus;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 3d6ffaabc7..ebd7917d49 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -735,6 +735,12 @@ typedef enum RISCVException {
 #define MIE_SSIE   (1 << IRQ_S_SOFT)
 #define MIE_USIE   (1 << IRQ_U_SOFT)
 
+/* Machine constants */
+#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
+#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
+#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
+#define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS))
+
 /* General PointerMasking CSR bits */
 #define PM_ENABLE   0x0001ULL
 #define PM_CURRENT  0x0002ULL
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 581b8c6380..b36161708a 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -376,6 +376,10 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 return best_irq;
 }
 
+/*
+ * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
+ * are returned in riscv_cpu_sirq_pending().
+ */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
 uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -398,9 +402,10 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 {
 uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
 ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs_f = env->mvip & env->mvien & ~env->mideleg & env->sie;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs, env->siprio);
+irqs | irqs_f, env->siprio);
 }
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
@@ -414,8 +419,8 @@ int riscv_cpu_vsirq_pending(CPURISCVState *env)
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
 int virq;
-uint64_t irqs, pending, mie, hsie, vsie;
 
 /* Determine interrupt enable state of all privilege modes */
 if (env->virt_enabled) {
@@ -441,8 +446,11 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->miprio);
 }
 
+/* Check for virtual S-mode interrupts. */
+irqs_f = env->mvip & (env->mvien & ~env->mideleg) & env->sie;
+
 /* Check HS-mode interrupts */
-irqs = pending & env->mideleg & ~en

[PATCH v4 2/6] target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.

2023-10-12 Thread Rajnesh Kanwal
RISCV_EXCP_SEMIHOST is set to 0x10, which can be a local interrupt id
as well. This change moves RISCV_EXCP_SEMIHOST to switch case so that
async flag check is performed before invoking semihosting logic.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu_helper.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 8c28241c18..aaeb1d0d5c 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1605,15 +1605,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 target_ulong htval = 0;
 target_ulong mtval2 = 0;
 
-if  (cause == RISCV_EXCP_SEMIHOST) {
-do_common_semihosting(cs);
-env->pc += 4;
-return;
-}
-
 if (!async) {
 /* set tval to badaddr for traps with address information */
 switch (cause) {
+case RISCV_EXCP_SEMIHOST:
+do_common_semihosting(cs);
+env->pc += 4;
+return;
 case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
 case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
 case RISCV_EXCP_LOAD_ADDR_MIS:
-- 
2.34.1




[PATCH v4 6/6] target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

2023-10-12 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from HS-mode
into VS-mode using hvien and hvip csrs. This also allows for IRQ filtering
from HS-mode.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows HS-mode to assert virtual interrupts to VS-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "6.3.2 Virtual
interrupts for VS level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Daniel Henrique Barboza 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|  14 +++
 target/riscv/cpu_helper.c |  48 +++---
 target/riscv/csr.c| 196 ++
 target/riscv/machine.c|   3 +
 5 files changed, 234 insertions(+), 30 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 6546634f9d..dbbea26a87 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -814,7 +814,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * mode and delegation registers, but respect individual enables
  */
 return riscv_cpu_all_pending(env) != 0 ||
-riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE ||
+riscv_cpu_vsirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 30f9481f45..7f61e17202 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -208,6 +208,12 @@ struct CPUArchState {
  */
 uint64_t sie;
 
+/*
+ * When hideleg[i]=0 and hvien[i]=1, vsie[i] is no more
+ * alias of sie[i] (mie[i]) and needs to be maintained separatly.
+ */
+uint64_t vsie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -242,6 +248,14 @@ struct CPUArchState {
 target_ulong hgeie;
 target_ulong hgeip;
 uint64_t htimedelta;
+uint64_t hvien;
+
+/*
+ * Bits VSSIP, VSTIP and VSEIP in hvip are maintained in mip. Other bits
+ * from 0:12 are reserved. Bits 13:63 are not aliased and must be 
separately
+ * maintain in hvip.
+ */
+uint64_t hvip;
 
 /* Hypervisor controlled virtual interrupt priorities */
 target_ulong hvictl;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index b36161708a..b7af69de53 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -377,8 +377,9 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 }
 
 /*
- * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
- * are returned in riscv_cpu_sirq_pending().
+ * Doesn't report interrupts inserted using mvip from M-mode firmware or
+ * using hvip bits 13:63 from HS-mode. Those are returned in
+ * riscv_cpu_sirq_pending() and riscv_cpu_vsirq_pending().
  */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
@@ -410,16 +411,23 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
 {
-uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
-(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg & env->hideleg;
+uint64_t irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+uint64_t vsbits;
+
+/* Bring VS-level bits to correct position */
+vsbits = irqs & VS_MODE_INTERRUPTS;
+irqs &= ~VS_MODE_INTERRUPTS;
+irqs |= vsbits >> 1;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs >> 1, env->hviprio);
+(irqs | irqs_f_vs), env->hviprio);
 }
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
-uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f, irqs_f_vs;
+uint64_t vsbits, irq_delegated;
 int virq;
 
 /* Determine interrupt enable state of all privilege modes */
@@ -456,12 +464,26 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->siprio);
 }
 
+/* Check for virtual VS-mode interrupts. */
+irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+
 /* Check VS-mode interrupts */
-irqs = pending & env->mideleg & env->hideleg & -vsie;
+irq_delegated = pending & env->mideleg & env->hideleg;
+
+/* Bring VS-level bits to correct position */
+vsbits = irq_delegated & VS_MODE_INTERRUPTS;
+irq_delegated &= ~VS_MODE_INTERRUPTS;
+irq_delegated |= vsbits >> 1;
+
+irqs = (irq_delegated | irqs_f_vs) & -vsie;
 if (irqs) {
 virq = riscv_cp

[PATCH v4 4/6] target/riscv: Split interrupt logic from riscv_cpu_update_mip.

2023-10-12 Thread Rajnesh Kanwal
This is to allow virtual interrupts to be inserted into S and VS
modes. Given virtual interrupts will be maintained in separate
mvip and hvip CSRs, riscv_cpu_update_mip will no longer be in the
path and interrupts need to be triggered for these cases from
rmw_hvip64 and rmw_mvip64 functions.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu.h|  1 +
 target/riscv/cpu_helper.c | 25 ++---
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index f8ffa5ee38..6fe32e6b38 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -463,6 +463,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_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 *),
  void *arg);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index aaeb1d0d5c..581b8c6380 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -620,11 +620,12 @@ 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_interrupt(CPURISCVState *env)
 {
+uint64_t gein, vsgein = 0, vstip = 0;
 CPUState *cs = env_cpu(env);
-uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
+
+QEMU_IOTHREAD_LOCK_GUARD();
 
 if (env->virt_enabled) {
 gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -633,15 +634,25 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, 
uint64_t mask,
 
 vstip = env->vstime_irq ? MIP_VSTIP : 0;
 
-QEMU_IOTHREAD_LOCK_GUARD();
-
-env->mip = (env->mip & ~mask) | (value & mask);
-
 if (env->mip | vsgein | vstip) {
 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
+}
+
+uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t 
value)
+{
+uint64_t old = env->mip;
+
+/* No need to update mip for VSTIP */
+mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
+
+QEMU_IOTHREAD_LOCK_GUARD();
+
+env->mip = (env->mip & ~mask) | (value & mask);
+
+riscv_cpu_interrupt(env);
 
 return old;
 }
-- 
2.34.1




[PATCH v4 1/6] target/riscv: Without H-mode mask all HS mode inturrupts in mie.

2023-10-12 Thread Rajnesh Kanwal
Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/csr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 4b4ab56c40..d99d954ff3 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1525,7 +1525,7 @@ static RISCVException rmw_mie64(CPURISCVState *env, int 
csrno,
 env->mie = (env->mie & ~mask) | (new_val & mask);
 
 if (!riscv_has_ext(env, RVH)) {
-env->mie &= ~((uint64_t)MIP_SGEIP);
+env->mie &= ~((uint64_t)HS_MODE_INTERRUPTS);
 }
 
 return RISCV_EXCP_NONE;
-- 
2.34.1




[PATCH v4 0/6] target/riscv: Add RISC-V Virtual IRQs and IRQ filtering support

2023-10-12 Thread Rajnesh Kanwal
This series adds M and HS-mode virtual interrupt and IRQ filtering support.
This allows inserting virtual interrupts from M/HS-mode into S/VS-mode
using mvien/hvien and mvip/hvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M/HS-mode to assert virtual interrupts to
S/VS-mode that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level" and "6.3.2 Virtual
interrupts for VS level".

Most of the testing is done by hacking around OpenSBI and linux host.
The changes for those can be found at [1] and [2].

It's my first touch on RISC-V qemu IRQ subsystem. Any feedback would
be much appreciated.

The change can also be found on github [3].

TODO: This change doesn't support delegating virtual interrupts injected
by M-mode to VS-mode by the Hypervisor. This is true for bits 13:63 only.

Thanks
Rajnesh

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf
[1]: https://github.com/rajnesh-kanwal/opensbi/tree/dev/rkanwal/irq_filter
[2]: https://github.com/rajnesh-kanwal/linux/commits/dev/rkanwal/aia_irq_filter
[3]: https://github.com/rajnesh-kanwal/qemu/tree/dev/rkanwal/riscv_irq_filter

v4:
 * Rebased the patches onto alister/riscv-to-apply.next. There were
   some rebasing conflicts due to code restructuring.

v3:
 * Rebased the patches and added reviewed-by tags.

v2:
 * Move RISCV_EXCP_SEMIHOST to switch case and remove special handling.
 * Fix linux-user build.

Rajnesh Kanwal (6):
  target/riscv: Without H-mode mask all HS mode inturrupts in mie.
  target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.
  target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled
  target/riscv: Split interrupt logic from riscv_cpu_update_mip.
  target/riscv: Add M-mode virtual interrupt and IRQ filtering support.
  target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

 target/riscv/cpu.c |   4 +-
 target/riscv/cpu.h |  23 ++
 target/riscv/cpu_bits.h|   6 +
 target/riscv/cpu_helper.c  |  99 ++--
 target/riscv/csr.c | 477 +
 target/riscv/machine.c |   6 +
 target/riscv/tcg/tcg-cpu.c |   7 +-
 7 files changed, 547 insertions(+), 75 deletions(-)

-- 
2.34.1




[PATCH v3 2/6] target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.

2023-10-11 Thread Rajnesh Kanwal
RISCV_EXCP_SEMIHOST is set to 0x10, which can be a local interrupt id
as well. This change moves RISCV_EXCP_SEMIHOST to switch case so that
async flag check is performed before invoking semihosting logic.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu_helper.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 3a02079290..8ffb31b607 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1606,15 +1606,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 target_ulong htval = 0;
 target_ulong mtval2 = 0;
 
-if  (cause == RISCV_EXCP_SEMIHOST) {
-do_common_semihosting(cs);
-env->pc += 4;
-return;
-}
-
 if (!async) {
 /* set tval to badaddr for traps with address information */
 switch (cause) {
+case RISCV_EXCP_SEMIHOST:
+do_common_semihosting(cs);
+env->pc += 4;
+return;
 case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
 case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
 case RISCV_EXCP_LOAD_ADDR_MIS:
-- 
2.34.1




[PATCH v3 5/6] target/riscv: Add M-mode virtual interrupt and IRQ filtering support.

2023-10-11 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from M-mode
into S-mode using mvien and mvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M-mode to assert virtual interrupts to S-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Daniel Henrique Barboza 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|   8 ++
 target/riscv/cpu_bits.h   |   6 +
 target/riscv/cpu_helper.c |  26 +++-
 target/riscv/csr.c| 279 ++
 target/riscv/machine.c|   3 +
 6 files changed, 289 insertions(+), 36 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 0e7620d1ad..96f2c38334 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -825,7 +825,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * Definition of the WFI instruction requires it to ignore the privilege
  * mode and delegation registers, but respect individual enables
  */
-return riscv_cpu_all_pending(env) != 0;
+return riscv_cpu_all_pending(env) != 0 ||
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7092aeb7f0..6dc4271c94 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -198,6 +198,12 @@ struct CPUArchState {
 uint64_t mie;
 uint64_t mideleg;
 
+/*
+ * When mideleg[i]=0 and mvien[i]=1, sie[i] is no more
+ * alias of mie[i] and needs to be maintained separatly.
+ */
+uint64_t sie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -218,6 +224,8 @@ struct CPUArchState {
 /* AIA CSRs */
 target_ulong miselect;
 target_ulong siselect;
+uint64_t mvien;
+uint64_t mvip;
 
 /* Hypervisor CSRs */
 target_ulong hstatus;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 3d6ffaabc7..ebd7917d49 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -735,6 +735,12 @@ typedef enum RISCVException {
 #define MIE_SSIE   (1 << IRQ_S_SOFT)
 #define MIE_USIE   (1 << IRQ_U_SOFT)
 
+/* Machine constants */
+#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
+#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
+#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
+#define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS))
+
 /* General PointerMasking CSR bits */
 #define PM_ENABLE   0x0001ULL
 #define PM_CURRENT  0x0002ULL
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index a182336cd2..4a27c4fa5e 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -377,6 +377,10 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 return best_irq;
 }
 
+/*
+ * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
+ * are returned in riscv_cpu_sirq_pending().
+ */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
 uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -399,9 +403,10 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 {
 uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
 ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs_f = env->mvip & env->mvien & ~env->mideleg & env->sie;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs, env->siprio);
+irqs | irqs_f, env->siprio);
 }
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
@@ -415,8 +420,8 @@ int riscv_cpu_vsirq_pending(CPURISCVState *env)
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
 int virq;
-uint64_t irqs, pending, mie, hsie, vsie;
 
 /* Determine interrupt enable state of all privilege modes */
 if (env->virt_enabled) {
@@ -442,8 +447,11 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->miprio);
 }
 
+/* Check for virtual S-mode interrupts. */
+irqs_f = env->mvip & (env->mvien & ~env->mideleg) & env->sie;
+
 /* Check HS-mode interrupts */
-irqs = pending & env->mideleg & ~en

[PATCH v3 4/6] target/riscv: Split interrupt logic from riscv_cpu_update_mip.

2023-10-11 Thread Rajnesh Kanwal
This is to allow virtual interrupts to be inserted into S and VS
modes. Given virtual interrupts will be maintained in separate
mvip and hvip CSRs, riscv_cpu_update_mip will no longer be in the
path and interrupts need to be triggered for these cases from
rmw_hvip64 and rmw_mvip64 functions.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu.h|  1 +
 target/riscv/cpu_helper.c | 25 ++---
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index ef9cf21c0c..7092aeb7f0 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -460,6 +460,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_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 *),
  void *arg);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 8ffb31b607..a182336cd2 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -621,11 +621,12 @@ 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_interrupt(CPURISCVState *env)
 {
+uint64_t gein, vsgein = 0, vstip = 0;
 CPUState *cs = env_cpu(env);
-uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
+
+QEMU_IOTHREAD_LOCK_GUARD();
 
 if (env->virt_enabled) {
 gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -634,15 +635,25 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, 
uint64_t mask,
 
 vstip = env->vstime_irq ? MIP_VSTIP : 0;
 
-QEMU_IOTHREAD_LOCK_GUARD();
-
-env->mip = (env->mip & ~mask) | (value & mask);
-
 if (env->mip | vsgein | vstip) {
 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
+}
+
+uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t 
value)
+{
+uint64_t old = env->mip;
+
+/* No need to update mip for VSTIP */
+mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
+
+QEMU_IOTHREAD_LOCK_GUARD();
+
+env->mip = (env->mip & ~mask) | (value & mask);
+
+riscv_cpu_interrupt(env);
 
 return old;
 }
-- 
2.34.1




[PATCH v3 6/6] target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

2023-10-11 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from HS-mode
into VS-mode using hvien and hvip csrs. This also allows for IRQ filtering
from HS-mode.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows HS-mode to assert virtual interrupts to VS-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "6.3.2 Virtual
interrupts for VS level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Daniel Henrique Barboza 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|  14 +++
 target/riscv/cpu_helper.c |  48 +++---
 target/riscv/csr.c| 196 ++
 target/riscv/machine.c|   3 +
 5 files changed, 234 insertions(+), 30 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 96f2c38334..841ba38cf8 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -826,7 +826,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * mode and delegation registers, but respect individual enables
  */
 return riscv_cpu_all_pending(env) != 0 ||
-riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE ||
+riscv_cpu_vsirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6dc4271c94..4195d01617 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -204,6 +204,12 @@ struct CPUArchState {
  */
 uint64_t sie;
 
+/*
+ * When hideleg[i]=0 and hvien[i]=1, vsie[i] is no more
+ * alias of sie[i] (mie[i]) and needs to be maintained separatly.
+ */
+uint64_t vsie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -238,6 +244,14 @@ struct CPUArchState {
 target_ulong hgeie;
 target_ulong hgeip;
 uint64_t htimedelta;
+uint64_t hvien;
+
+/*
+ * Bits VSSIP, VSTIP and VSEIP in hvip are maintained in mip. Other bits
+ * from 0:12 are reserved. Bits 13:63 are not aliased and must be 
separately
+ * maintain in hvip.
+ */
+uint64_t hvip;
 
 /* Hypervisor controlled virtual interrupt priorities */
 target_ulong hvictl;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 4a27c4fa5e..0594c8b1ae 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -378,8 +378,9 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 }
 
 /*
- * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
- * are returned in riscv_cpu_sirq_pending().
+ * Doesn't report interrupts inserted using mvip from M-mode firmware or
+ * using hvip bits 13:63 from HS-mode. Those are returned in
+ * riscv_cpu_sirq_pending() and riscv_cpu_vsirq_pending().
  */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
@@ -411,16 +412,23 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
 {
-uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
-(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg & env->hideleg;
+uint64_t irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+uint64_t vsbits;
+
+/* Bring VS-level bits to correct position */
+vsbits = irqs & VS_MODE_INTERRUPTS;
+irqs &= ~VS_MODE_INTERRUPTS;
+irqs |= vsbits >> 1;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs >> 1, env->hviprio);
+(irqs | irqs_f_vs), env->hviprio);
 }
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
-uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f, irqs_f_vs;
+uint64_t vsbits, irq_delegated;
 int virq;
 
 /* Determine interrupt enable state of all privilege modes */
@@ -457,12 +465,26 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->siprio);
 }
 
+/* Check for virtual VS-mode interrupts. */
+irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+
 /* Check VS-mode interrupts */
-irqs = pending & env->mideleg & env->hideleg & -vsie;
+irq_delegated = pending & env->mideleg & env->hideleg;
+
+/* Bring VS-level bits to correct position */
+vsbits = irq_delegated & VS_MODE_INTERRUPTS;
+irq_delegated &= ~VS_MODE_INTERRUPTS;
+irq_delegated |= vsbits >> 1;
+
+irqs = (irq_delegated | irqs_f_vs) & -vsie;
 if (irqs) {
 virq = riscv_cp

[PATCH v3 0/6] target/riscv: Add RISC-V Virtual IRQs and IRQ filtering support

2023-10-11 Thread Rajnesh Kanwal
This series adds M and HS-mode virtual interrupt and IRQ filtering support.
This allows inserting virtual interrupts from M/HS-mode into S/VS-mode
using mvien/hvien and mvip/hvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M/HS-mode to assert virtual interrupts to
S/VS-mode that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level" and "6.3.2 Virtual
interrupts for VS level".

Most of the testing is done by hacking around OpenSBI and linux host.
The changes for those can be found at [1] and [2].

It's my first touch on RISC-V qemu IRQ subsystem. Any feedback would
be much appreciated.

The change can also be found on github [3].

TODO: This change doesn't support delegating virtual interrupts injected
by M-mode to VS-mode by the Hypervisor. This is true for bits 13:63 only.

Thanks
Rajnesh

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf
[1]: https://github.com/rajnesh-kanwal/opensbi/tree/dev/rkanwal/irq_filter
[2]: https://github.com/rajnesh-kanwal/linux/commits/dev/rkanwal/aia_irq_filter
[3]: https://github.com/rajnesh-kanwal/qemu/tree/dev/rkanwal/riscv_irq_filter

v3:
 * Rebased the patches and added reviewed-by tags.

v2:
 * Move RISCV_EXCP_SEMIHOST to switch case and remove special handling.
 * Fix linux-user build.

Rajnesh Kanwal (6):
  target/riscv: Without H-mode mask all HS mode inturrupts in mie.
  target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.
  target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled
  target/riscv: Split interrupt logic from riscv_cpu_update_mip.
  target/riscv: Add M-mode virtual interrupt and IRQ filtering support.
  target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

 target/riscv/cpu.c|  11 +-
 target/riscv/cpu.h|  23 ++
 target/riscv/cpu_bits.h   |   6 +
 target/riscv/cpu_helper.c |  99 +---
 target/riscv/csr.c| 477 ++
 target/riscv/machine.c|   6 +
 6 files changed, 547 insertions(+), 75 deletions(-)

-- 
2.34.1




[PATCH v3 3/6] target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled

2023-10-11 Thread Rajnesh Kanwal
With H-Ext supported, VS bits are all hardwired to one in MIDELEG
denoting always delegated interrupts. This is being done in rmw_mideleg
but given mideleg is used in other places when routing interrupts
this change initializes it in riscv_cpu_realize to be on the safe side.

Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/cpu.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ac2b94b6a6..0e7620d1ad 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1492,7 +1492,12 @@ static void riscv_cpu_realize_tcg(DeviceState *dev, 
Error **errp)
 cpu->pmu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
   riscv_pmu_timer_cb, cpu);
 }
- }
+}
+
+/* With H-Ext, VSSIP, VSTIP, VSEIP and SGEIP are hardwired to one. */
+if (riscv_has_ext(env, RVH)) {
+env->mideleg = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP | MIP_SGEIP;
+}
 #endif
 }
 
-- 
2.34.1




[PATCH v3 1/6] target/riscv: Without H-mode mask all HS mode inturrupts in mie.

2023-10-11 Thread Rajnesh Kanwal
Signed-off-by: Rajnesh Kanwal 
Reviewed-by: Alistair Francis 
---
 target/riscv/csr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 85a31dc420..0241c77719 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1524,7 +1524,7 @@ static RISCVException rmw_mie64(CPURISCVState *env, int 
csrno,
 env->mie = (env->mie & ~mask) | (new_val & mask);
 
 if (!riscv_has_ext(env, RVH)) {
-env->mie &= ~((uint64_t)MIP_SGEIP);
+env->mie &= ~((uint64_t)HS_MODE_INTERRUPTS);
 }
 
 return RISCV_EXCP_NONE;
-- 
2.34.1




Re: [PATCH v2 0/6] target/riscv: Add RISC-V Virtual IRQs and IRQ filtering support

2023-09-21 Thread Rajnesh Kanwal
Hey Daniel,

Sorry I was on holiday. There is no new work on this AFAIK. I will
rebase and send a new version for this shortly.

Thanks
Rajnesh

On Wed, Sep 6, 2023 at 3:38 PM Daniel Henrique Barboza
 wrote:
>
> Hey,
>
>
> What's the latest on this work? It seems that all patches are acked:
>
> https://lore.kernel.org/qemu-riscv/20230526162308.22892-1-rkan...@rivosinc.com/
>
>
> It'll probably conflict with current Alistair's riscv-to-apply.next though, so
> perhaps Rajnesh could gather the acks and send a rebased version.
>
>
> Thanks,
>
> Daniel
>
>
> On 5/26/23 13:23, Rajnesh Kanwal wrote:
> > This series adds M and HS-mode virtual interrupt and IRQ filtering support.
> > This allows inserting virtual interrupts from M/HS-mode into S/VS-mode
> > using mvien/hvien and mvip/hvip csrs. IRQ filtering is a use case of
> > this change, i-e M-mode can stop delegating an interrupt to S-mode and
> > instead enable it in MIE and receive those interrupts in M-mode and then
> > selectively inject the interrupt using mvien and mvip.
> >
> > Also, the spec doesn't mandate the interrupt to be actually supported
> > in hardware. Which allows M/HS-mode to assert virtual interrupts to
> > S/VS-mode that have no connection to any real interrupt events.
> >
> > This is defined as part of the AIA specification [0], "5.3 Interrupt
> > filtering and virtual interrupts for supervisor level" and "6.3.2 Virtual
> > interrupts for VS level".
> >
> > Most of the testing is done by hacking around OpenSBI and linux host.
> > The changes for those can be found at [1] and [2].
> >
> > It's my first touch on RISC-V qemu IRQ subsystem. Any feedback would
> > be much appreciated.
> >
> > The change can also be found on github [3].
> >
> > TODO: This change doesn't support delegating virtual interrupts injected
> > by M-mode to VS-mode by the Hypervisor. This is true for bits 13:63 only.
> >
> > Thanks
> > Rajnesh
> >
> > [0]: 
> > https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf
> > [1]: https://github.com/rajnesh-kanwal/opensbi/tree/dev/rkanwal/irq_filter
> > [2]: 
> > https://github.com/rajnesh-kanwal/linux/commits/dev/rkanwal/aia_irq_filter
> > [3]: 
> > https://github.com/rajnesh-kanwal/qemu/tree/dev/rkanwal/riscv_irq_filter
> >
> > v2:
> >   * Move RISCV_EXCP_SEMIHOST to switch case and remove special handling.
> >   * Fix linux-user build.
> >
> > Rajnesh Kanwal (6):
> >target/riscv: Without H-mode mask all HS mode inturrupts in mie.
> >target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.
> >target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled
> >target/riscv: Split interrupt logic from riscv_cpu_update_mip.
> >target/riscv: Add M-mode virtual interrupt and IRQ filtering support.
> >target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.
> >
> >   target/riscv/cpu.c|   9 +-
> >   target/riscv/cpu.h|  23 ++
> >   target/riscv/cpu_bits.h   |   6 +
> >   target/riscv/cpu_helper.c |  99 +---
> >   target/riscv/csr.c| 477 ++
> >   target/riscv/machine.c|   6 +
> >   6 files changed, 546 insertions(+), 74 deletions(-)
> >



Re: [PATCH 6/6] target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

2023-05-26 Thread Rajnesh Kanwal
On Mon, May 22, 2023 at 6:18 PM Daniel Henrique Barboza
 wrote:
>
>
>
> On 5/18/23 08:38, Rajnesh Kanwal wrote:
> > This change adds support for inserting virtual interrupts from HS-mode
> > into VS-mode using hvien and hvip csrs. This also allows for IRQ filtering
> > from HS-mode.
> >
> > Also, the spec doesn't mandate the interrupt to be actually supported
> > in hardware. Which allows HS-mode to assert virtual interrupts to VS-mode
> > that have no connection to any real interrupt events.
> >
> > This is defined as part of the AIA specification [0], "6.3.2 Virtual
> > interrupts for VS level".
> >
> > [0]: 
> > https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf
> >
> > Signed-off-by: Rajnesh Kanwal 
> > ---
> >   target/riscv/cpu.c|   3 +-
> >   target/riscv/cpu.h|  14 +++
> >   target/riscv/cpu_helper.c |  48 +++---
> >   target/riscv/csr.c| 196 ++
> >   target/riscv/machine.c|   3 +
> >   5 files changed, 234 insertions(+), 30 deletions(-)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index 9557194a21..c2b05d4c37 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -713,7 +713,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
> >* mode and delegation registers, but respect individual enables
> >*/
> >   return riscv_cpu_all_pending(env) != 0 ||
> > -riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
> > +riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE ||
> > +riscv_cpu_vsirq_pending(env) != RISCV_EXCP_NONE;
> >   #else
> >   return true;
> >   #endif
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index 07cf656471..3e10eee38f 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -196,6 +196,12 @@ struct CPUArchState {
> >*/
> >   uint64_t sie;
> >
> > +/*
> > + * When hideleg[i]=0 and hvien[i]=1, vsie[i] is no more
> > + * alias of sie[i] (mie[i]) and needs to be maintained separatly.
> > + */
> > +uint64_t vsie;
> > +
> >   target_ulong satp;   /* since: priv-1.10.0 */
> >   target_ulong stval;
> >   target_ulong medeleg;
> > @@ -230,6 +236,14 @@ struct CPUArchState {
> >   target_ulong hgeie;
> >   target_ulong hgeip;
> >   uint64_t htimedelta;
> > +uint64_t hvien;
> > +
> > +/*
> > + * Bits VSSIP, VSTIP and VSEIP in hvip are maintained in mip. Other 
> > bits
> > + * from 0:12 are reserved. Bits 13:63 are not aliased and must be 
> > separately
> > + * maintain in hvip.
> > + */
> > +uint64_t hvip;
> >
> >   /* Hypervisor controlled virtual interrupt priorities */
> >   target_ulong hvictl;
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index 681b4ae811..80bdd4cf5a 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -366,8 +366,9 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> >   }
> >
> >   /*
> > - * Doesn't report interrupts inserted using mvip from M-mode firmware. 
> > Those
> > - * are returned in riscv_cpu_sirq_pending().
> > + * Doesn't report interrupts inserted using mvip from M-mode firmware or
> > + * using hvip bits 13:63 from HS-mode. Those are returned in
> > + * riscv_cpu_sirq_pending() and riscv_cpu_vsirq_pending().
> >*/
> >   uint64_t riscv_cpu_all_pending(CPURISCVState *env)
> >   {
> > @@ -399,16 +400,23 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
> >
> >   int riscv_cpu_vsirq_pending(CPURISCVState *env)
> >   {
> > -uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
> > -(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg & 
> > env->hideleg;
> > +uint64_t irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & 
> > env->vsie;
> > +uint64_t vsbits;
> > +
> > +/* Bring VS-level bits to correct position */
> > +vsbits = irqs & VS_MODE_INTERRUPTS;
> > +irqs &= ~VS_MODE_INTERRUPTS;
> > +irqs |= vsbits >> 1;
> >
> >   return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
> > -irqs >> 1, env->hviprio);
> > +

[PATCH v2 6/6] target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

2023-05-26 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from HS-mode
into VS-mode using hvien and hvip csrs. This also allows for IRQ filtering
from HS-mode.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows HS-mode to assert virtual interrupts to VS-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "6.3.2 Virtual
interrupts for VS level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|  14 +++
 target/riscv/cpu_helper.c |  48 +++---
 target/riscv/csr.c| 196 ++
 target/riscv/machine.c|   3 +
 5 files changed, 234 insertions(+), 30 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7c4999431a..6f2f8f21cc 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -713,7 +713,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * mode and delegation registers, but respect individual enables
  */
 return riscv_cpu_all_pending(env) != 0 ||
-riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE ||
+riscv_cpu_vsirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 07cf656471..3e10eee38f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -196,6 +196,12 @@ struct CPUArchState {
  */
 uint64_t sie;
 
+/*
+ * When hideleg[i]=0 and hvien[i]=1, vsie[i] is no more
+ * alias of sie[i] (mie[i]) and needs to be maintained separatly.
+ */
+uint64_t vsie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -230,6 +236,14 @@ struct CPUArchState {
 target_ulong hgeie;
 target_ulong hgeip;
 uint64_t htimedelta;
+uint64_t hvien;
+
+/*
+ * Bits VSSIP, VSTIP and VSEIP in hvip are maintained in mip. Other bits
+ * from 0:12 are reserved. Bits 13:63 are not aliased and must be 
separately
+ * maintain in hvip.
+ */
+uint64_t hvip;
 
 /* Hypervisor controlled virtual interrupt priorities */
 target_ulong hvictl;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 6567ddef7b..fd7dae9b68 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -366,8 +366,9 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 }
 
 /*
- * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
- * are returned in riscv_cpu_sirq_pending().
+ * Doesn't report interrupts inserted using mvip from M-mode firmware or
+ * using hvip bits 13:63 from HS-mode. Those are returned in
+ * riscv_cpu_sirq_pending() and riscv_cpu_vsirq_pending().
  */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
@@ -399,16 +400,23 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
 {
-uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
-(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg & env->hideleg;
+uint64_t irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+uint64_t vsbits;
+
+/* Bring VS-level bits to correct position */
+vsbits = irqs & VS_MODE_INTERRUPTS;
+irqs &= ~VS_MODE_INTERRUPTS;
+irqs |= vsbits >> 1;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs >> 1, env->hviprio);
+(irqs | irqs_f_vs), env->hviprio);
 }
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
-uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f, irqs_f_vs;
+uint64_t vsbits, irq_delegated;
 int virq;
 
 /* Determine interrupt enable state of all privilege modes */
@@ -445,12 +453,26 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->siprio);
 }
 
+/* Check for virtual VS-mode interrupts. */
+irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+
 /* Check VS-mode interrupts */
-irqs = pending & env->mideleg & env->hideleg & -vsie;
+irq_delegated = pending & env->mideleg & env->hideleg;
+
+/* Bring VS-level bits to correct position */
+vsbits = irq_delegated & VS_MODE_INTERRUPTS;
+irq_delegated &= ~VS_MODE_INTERRUPTS;
+irq_delegated |= vsbits >> 1;
+
+irqs = (irq_delegated | irqs_f_vs) & -vsie;
 if (irqs) {
 virq = riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-  

[PATCH v2 4/6] target/riscv: Split interrupt logic from riscv_cpu_update_mip.

2023-05-26 Thread Rajnesh Kanwal
This is to allow virtual interrupts to be inserted into S and VS
modes. Given virtual interrupts will be maintained in separate
mvip and hvip CSRs, riscv_cpu_update_mip will no longer be in the
path and interrupts need to be triggered for these cases from
rmw_hvip64 and rmw_mvip64 functions.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.h|  1 +
 target/riscv/cpu_helper.c | 25 ++---
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index de7e43126a..de55bfb775 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -562,6 +562,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_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 *),
  void *arg);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index b25ee179e9..c79ec4db76 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -609,11 +609,12 @@ 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_interrupt(CPURISCVState *env)
 {
+uint64_t gein, vsgein = 0, vstip = 0;
 CPUState *cs = env_cpu(env);
-uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
+
+QEMU_IOTHREAD_LOCK_GUARD();
 
 if (env->virt_enabled) {
 gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -622,15 +623,25 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, 
uint64_t mask,
 
 vstip = env->vstime_irq ? MIP_VSTIP : 0;
 
-QEMU_IOTHREAD_LOCK_GUARD();
-
-env->mip = (env->mip & ~mask) | (value & mask);
-
 if (env->mip | vsgein | vstip) {
 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
+}
+
+uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t 
value)
+{
+uint64_t old = env->mip;
+
+/* No need to update mip for VSTIP */
+mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
+
+QEMU_IOTHREAD_LOCK_GUARD();
+
+env->mip = (env->mip & ~mask) | (value & mask);
+
+riscv_cpu_interrupt(env);
 
 return old;
 }
-- 
2.25.1




[PATCH v2 0/6] target/riscv: Add RISC-V Virtual IRQs and IRQ filtering support

2023-05-26 Thread Rajnesh Kanwal
This series adds M and HS-mode virtual interrupt and IRQ filtering support.
This allows inserting virtual interrupts from M/HS-mode into S/VS-mode
using mvien/hvien and mvip/hvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and 
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M/HS-mode to assert virtual interrupts to
S/VS-mode that have no connection to any real interrupt events.
 
This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level" and "6.3.2 Virtual
interrupts for VS level".

Most of the testing is done by hacking around OpenSBI and linux host.
The changes for those can be found at [1] and [2].

It's my first touch on RISC-V qemu IRQ subsystem. Any feedback would
be much appreciated.

The change can also be found on github [3].

TODO: This change doesn't support delegating virtual interrupts injected 
by M-mode to VS-mode by the Hypervisor. This is true for bits 13:63 only.

Thanks
Rajnesh

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf
[1]: https://github.com/rajnesh-kanwal/opensbi/tree/dev/rkanwal/irq_filter
[2]: https://github.com/rajnesh-kanwal/linux/commits/dev/rkanwal/aia_irq_filter
[3]: https://github.com/rajnesh-kanwal/qemu/tree/dev/rkanwal/riscv_irq_filter

v2:
 * Move RISCV_EXCP_SEMIHOST to switch case and remove special handling.
 * Fix linux-user build.

Rajnesh Kanwal (6):
  target/riscv: Without H-mode mask all HS mode inturrupts in mie.
  target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.
  target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled
  target/riscv: Split interrupt logic from riscv_cpu_update_mip.
  target/riscv: Add M-mode virtual interrupt and IRQ filtering support.
  target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

 target/riscv/cpu.c|   9 +-
 target/riscv/cpu.h|  23 ++
 target/riscv/cpu_bits.h   |   6 +
 target/riscv/cpu_helper.c |  99 +---
 target/riscv/csr.c| 477 ++
 target/riscv/machine.c|   6 +
 6 files changed, 546 insertions(+), 74 deletions(-)

-- 
2.25.1




[PATCH v2 5/6] target/riscv: Add M-mode virtual interrupt and IRQ filtering support.

2023-05-26 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from M-mode
into S-mode using mvien and mvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M-mode to assert virtual interrupts to S-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|   8 ++
 target/riscv/cpu_bits.h   |   6 +
 target/riscv/cpu_helper.c |  26 +++-
 target/riscv/csr.c| 279 ++
 target/riscv/machine.c|   3 +
 6 files changed, 289 insertions(+), 36 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 269a094f42..7c4999431a 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -712,7 +712,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * Definition of the WFI instruction requires it to ignore the privilege
  * mode and delegation registers, but respect individual enables
  */
-return riscv_cpu_all_pending(env) != 0;
+return riscv_cpu_all_pending(env) != 0 ||
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index de55bfb775..07cf656471 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -190,6 +190,12 @@ struct CPUArchState {
 uint64_t mie;
 uint64_t mideleg;
 
+/*
+ * When mideleg[i]=0 and mvien[i]=1, sie[i] is no more
+ * alias of mie[i] and needs to be maintained separatly.
+ */
+uint64_t sie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -210,6 +216,8 @@ struct CPUArchState {
 /* AIA CSRs */
 target_ulong miselect;
 target_ulong siselect;
+uint64_t mvien;
+uint64_t mvip;
 
 /* Hypervisor CSRs */
 target_ulong hstatus;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 59f0ffd9e1..0d32d2a5a7 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -735,6 +735,12 @@ typedef enum RISCVException {
 #define MIE_SSIE   (1 << IRQ_S_SOFT)
 #define MIE_USIE   (1 << IRQ_U_SOFT)
 
+/* Machine constants */
+#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
+#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
+#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
+#define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS))
+
 /* General PointerMasking CSR bits */
 #define PM_ENABLE   0x0001ULL
 #define PM_CURRENT  0x0002ULL
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index c79ec4db76..6567ddef7b 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -365,6 +365,10 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 return best_irq;
 }
 
+/*
+ * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
+ * are returned in riscv_cpu_sirq_pending().
+ */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
 uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -387,9 +391,10 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 {
 uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
 ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs_f = env->mvip & env->mvien & ~env->mideleg & env->sie;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs, env->siprio);
+irqs | irqs_f, env->siprio);
 }
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
@@ -403,8 +408,8 @@ int riscv_cpu_vsirq_pending(CPURISCVState *env)
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
 int virq;
-uint64_t irqs, pending, mie, hsie, vsie;
 
 /* Determine interrupt enable state of all privilege modes */
 if (env->virt_enabled) {
@@ -430,8 +435,11 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->miprio);
 }
 
+/* Check for virtual S-mode interrupts. */
+irqs_f = env->mvip & (env->mvien & ~env->mideleg) & env->sie;
+
 /* Check HS-mode interrupts */
-irqs = pending & env->mideleg & ~env->hideleg &

[PATCH v2 3/6] target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled

2023-05-26 Thread Rajnesh Kanwal
With H-Ext supported, VS bits are all hardwired to one in MIDELEG
denoting always delegated interrupts. This is being done in rmw_mideleg
but given mideleg is used in other places when routing interrupts
this change initializes it in riscv_cpu_realize to be on the safe side.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index db0875fb43..269a094f42 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1280,6 +1280,11 @@ static void riscv_cpu_realize(DeviceState *dev, Error 
**errp)
   riscv_pmu_timer_cb, cpu);
 }
  }
+
+/* With H-Ext, VSSIP, VSTIP, VSEIP and SGEIP are hardwired to one. */
+if (riscv_has_ext(env, RVH)) {
+env->mideleg = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP | MIP_SGEIP;
+}
 #endif
 
 riscv_cpu_finalize_features(cpu, _err);
-- 
2.25.1




[PATCH v2 2/6] target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.

2023-05-26 Thread Rajnesh Kanwal
RISCV_EXCP_SEMIHOST is set to 0x10, which can be a local interrupt id
as well. This change moves RISCV_EXCP_SEMIHOST to switch case so that
async flag check is performed before invoking semihosting logic.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu_helper.c | 10 --
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 57d04385f1..b25ee179e9 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1602,15 +1602,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 target_ulong htval = 0;
 target_ulong mtval2 = 0;
 
-if  (cause == RISCV_EXCP_SEMIHOST) {
-do_common_semihosting(cs);
-env->pc += 4;
-return;
-}
-
 if (!async) {
 /* set tval to badaddr for traps with address information */
 switch (cause) {
+case RISCV_EXCP_SEMIHOST:
+do_common_semihosting(cs);
+env->pc += 4;
+return;
 case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
 case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
 case RISCV_EXCP_LOAD_ADDR_MIS:
-- 
2.25.1




[PATCH v2 1/6] target/riscv: Without H-mode mask all HS mode inturrupts in mie.

2023-05-26 Thread Rajnesh Kanwal
Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/csr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 4451bd1263..041f0b3e2e 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1522,7 +1522,7 @@ static RISCVException rmw_mie64(CPURISCVState *env, int 
csrno,
 env->mie = (env->mie & ~mask) | (new_val & mask);
 
 if (!riscv_has_ext(env, RVH)) {
-env->mie &= ~((uint64_t)MIP_SGEIP);
+env->mie &= ~((uint64_t)HS_MODE_INTERRUPTS);
 }
 
 return RISCV_EXCP_NONE;
-- 
2.25.1




Re: [PATCH 2/6] target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.

2023-05-18 Thread Rajnesh Kanwal
On Thu, May 18, 2023 at 4:21 PM Loïc Lefort  wrote:
>
> Is there a reason to keep RISCV_EXCP_SEMIHOST handling separate from other 
> exceptions?
> Otherwise it could be moved in the switch block just a few lines below.

I agree. I will move it to the switch in the next series.

Thanks

>
> On Thu, May 18, 2023 at 1:39 PM Rajnesh Kanwal  wrote:
>>
>> RISCV_EXCP_SEMIHOST is set to 0x10, which can also be a local
>> interrupt as well. This change adds a check for async flag
>> before invoking semihosting logic.
>>
>> Signed-off-by: Rajnesh Kanwal 
>> ---
>>  target/riscv/cpu_helper.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
>> index 57d04385f1..c78a2a9514 100644
>> --- a/target/riscv/cpu_helper.c
>> +++ b/target/riscv/cpu_helper.c
>> @@ -1602,7 +1602,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>>  target_ulong htval = 0;
>>  target_ulong mtval2 = 0;
>>
>> -if  (cause == RISCV_EXCP_SEMIHOST) {
>> +if  (!async && cause == RISCV_EXCP_SEMIHOST) {
>>  do_common_semihosting(cs);
>>  env->pc += 4;
>>  return;
>> --
>> 2.25.1
>>
>>



[PATCH 3/6] target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled

2023-05-18 Thread Rajnesh Kanwal
With H-Ext supported, VS bits are all hardwired to one in MIDELEG
denoting always delegated interrupts. This is being done in rmw_mideleg
but given mideleg is used in other places when routing interrupts
this change initializes it in riscv_cpu_realize to be on the safe side.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index db0875fb43..90460cfe64 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1288,6 +1288,11 @@ static void riscv_cpu_realize(DeviceState *dev, Error 
**errp)
 return;
 }
 
+/* With H-Ext VSSIP, VSTIP, VSEIP and SGEIP are hardwired to one. */
+if (riscv_has_ext(env, RVH)) {
+env->mideleg = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP | MIP_SGEIP;
+}
+
 riscv_cpu_register_gdb_regs_for_features(cs);
 
 qemu_init_vcpu(cs);
-- 
2.25.1




[PATCH 2/6] target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.

2023-05-18 Thread Rajnesh Kanwal
RISCV_EXCP_SEMIHOST is set to 0x10, which can also be a local
interrupt as well. This change adds a check for async flag
before invoking semihosting logic.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu_helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 57d04385f1..c78a2a9514 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1602,7 +1602,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 target_ulong htval = 0;
 target_ulong mtval2 = 0;
 
-if  (cause == RISCV_EXCP_SEMIHOST) {
+if  (!async && cause == RISCV_EXCP_SEMIHOST) {
 do_common_semihosting(cs);
 env->pc += 4;
 return;
-- 
2.25.1




[PATCH 6/6] target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

2023-05-18 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from HS-mode
into VS-mode using hvien and hvip csrs. This also allows for IRQ filtering
from HS-mode.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows HS-mode to assert virtual interrupts to VS-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "6.3.2 Virtual
interrupts for VS level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|  14 +++
 target/riscv/cpu_helper.c |  48 +++---
 target/riscv/csr.c| 196 ++
 target/riscv/machine.c|   3 +
 5 files changed, 234 insertions(+), 30 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 9557194a21..c2b05d4c37 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -713,7 +713,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * mode and delegation registers, but respect individual enables
  */
 return riscv_cpu_all_pending(env) != 0 ||
-riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE ||
+riscv_cpu_vsirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 07cf656471..3e10eee38f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -196,6 +196,12 @@ struct CPUArchState {
  */
 uint64_t sie;
 
+/*
+ * When hideleg[i]=0 and hvien[i]=1, vsie[i] is no more
+ * alias of sie[i] (mie[i]) and needs to be maintained separatly.
+ */
+uint64_t vsie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -230,6 +236,14 @@ struct CPUArchState {
 target_ulong hgeie;
 target_ulong hgeip;
 uint64_t htimedelta;
+uint64_t hvien;
+
+/*
+ * Bits VSSIP, VSTIP and VSEIP in hvip are maintained in mip. Other bits
+ * from 0:12 are reserved. Bits 13:63 are not aliased and must be 
separately
+ * maintain in hvip.
+ */
+uint64_t hvip;
 
 /* Hypervisor controlled virtual interrupt priorities */
 target_ulong hvictl;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 681b4ae811..80bdd4cf5a 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -366,8 +366,9 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 }
 
 /*
- * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
- * are returned in riscv_cpu_sirq_pending().
+ * Doesn't report interrupts inserted using mvip from M-mode firmware or
+ * using hvip bits 13:63 from HS-mode. Those are returned in
+ * riscv_cpu_sirq_pending() and riscv_cpu_vsirq_pending().
  */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
@@ -399,16 +400,23 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
 {
-uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
-(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg & env->hideleg;
+uint64_t irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+uint64_t vsbits;
+
+/* Bring VS-level bits to correct position */
+vsbits = irqs & VS_MODE_INTERRUPTS;
+irqs &= ~VS_MODE_INTERRUPTS;
+irqs |= vsbits >> 1;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs >> 1, env->hviprio);
+(irqs | irqs_f_vs), env->hviprio);
 }
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
-uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f, irqs_f_vs;
+uint64_t vsbits, irq_delegated;
 int virq;
 
 /* Determine interrupt enable state of all privilege modes */
@@ -445,12 +453,26 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->siprio);
 }
 
+/* Check for virtual VS-mode interrupts. */
+irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+
 /* Check VS-mode interrupts */
-irqs = pending & env->mideleg & env->hideleg & -vsie;
+irq_delegated = pending & env->mideleg & env->hideleg;
+
+/* Bring VS-level bits to correct position */
+vsbits = irq_delegated & VS_MODE_INTERRUPTS;
+irq_delegated &= ~VS_MODE_INTERRUPTS;
+irq_delegated |= vsbits >> 1;
+
+irqs = (irq_delegated | irqs_f_vs) & -vsie;
 if (irqs) {
 virq = riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-  

[PATCH 4/6] target/riscv: Split interrupt logic from riscv_cpu_update_mip.

2023-05-18 Thread Rajnesh Kanwal
This is to allow virtual interrupts to be inserted into S and VS
modes. Given virtual interrupts will be maintained in separate
mvip and hvip CSRs, riscv_cpu_update_mip will no longer be in the
path and interrupts need to be triggered for these cases from
rmw_hvip64 and rmw_mvip64 functions.

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.h|  1 +
 target/riscv/cpu_helper.c | 21 -
 2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index de7e43126a..de55bfb775 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -562,6 +562,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_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 *),
  void *arg);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index c78a2a9514..035437e0fb 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -609,11 +609,10 @@ 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_interrupt(CPURISCVState *env)
 {
+uint64_t gein, vsgein = 0, vstip = 0;
 CPUState *cs = env_cpu(env);
-uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
 
 if (env->virt_enabled) {
 gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -624,13 +623,25 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, 
uint64_t mask,
 
 QEMU_IOTHREAD_LOCK_GUARD();
 
-env->mip = (env->mip & ~mask) | (value & mask);
-
 if (env->mip | vsgein | vstip) {
 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 } else {
 cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
 }
+}
+
+uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t 
value)
+{
+uint64_t old = env->mip;
+
+/* No need to update mip for VSTIP */
+mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
+
+QEMU_IOTHREAD_LOCK_GUARD();
+
+env->mip = (env->mip & ~mask) | (value & mask);
+
+riscv_cpu_interrupt(env);
 
 return old;
 }
-- 
2.25.1




[PATCH 0/6] Add RISC-V Virtual IRQs and IRQ filtering support

2023-05-18 Thread Rajnesh Kanwal
This series adds M and HS-mode virtual interrupt and IRQ filtering support.
This allows inserting virtual interrupts from M/HS-mode into S/VS-mode
using mvien/hvien and mvip/hvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and 
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M/HS-mode to assert virtual interrupts to
S/VS-mode that have no connection to any real interrupt events.
 
This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level" and "6.3.2 Virtual
interrupts for VS level".

Most of the testing is done by hacking around OpenSBI and linux host.
The changes for those can be found at [2] and [3].

It's my first touch on RISC-V qemu IRQ subsystem. Any feedback would
be much appreciated.

The change can also be found on github [1].

TODO: This change doesn't support delegating virtual interrupts injected 
by M-mode to VS-mode by the Hypervisor. This is true for bits 13:63 only.

Thanks
Rajnesh

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf
[1]: https://github.com/rajnesh-kanwal/qemu/tree/dev/rkanwal/riscv_irq_filter
[2]: https://github.com/rajnesh-kanwal/opensbi/tree/dev/rkanwal/irq_filter
[3]: https://github.com/rajnesh-kanwal/linux/commits/dev/rkanwal/aia_irq_filter

Rajnesh Kanwal (6):
  target/riscv: Without H-mode mask all HS mode inturrupts in mie.
  target/riscv: Check for async flag in case of RISCV_EXCP_SEMIHOST.
  target/riscv: Set VS* bits to one in mideleg when H-Ext is enabled
  target/riscv: Split interrupt logic from riscv_cpu_update_mip.
  target/riscv: Add M-mode virtual interrupt and IRQ filtering support.
  target/riscv: Add HS-mode virtual interrupt and IRQ filtering support.

 target/riscv/cpu.c|   9 +-
 target/riscv/cpu.h|  23 ++
 target/riscv/cpu_bits.h   |   6 +
 target/riscv/cpu_helper.c |  87 +--
 target/riscv/csr.c| 477 ++
 target/riscv/machine.c|   6 +
 6 files changed, 541 insertions(+), 67 deletions(-)

-- 
2.25.1




[PATCH 1/6] target/riscv: Without H-mode mask all HS mode inturrupts in mie.

2023-05-18 Thread Rajnesh Kanwal
Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/csr.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 4451bd1263..041f0b3e2e 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1522,7 +1522,7 @@ static RISCVException rmw_mie64(CPURISCVState *env, int 
csrno,
 env->mie = (env->mie & ~mask) | (new_val & mask);
 
 if (!riscv_has_ext(env, RVH)) {
-env->mie &= ~((uint64_t)MIP_SGEIP);
+env->mie &= ~((uint64_t)HS_MODE_INTERRUPTS);
 }
 
 return RISCV_EXCP_NONE;
-- 
2.25.1




[PATCH 5/6] target/riscv: Add M-mode virtual interrupt and IRQ filtering support.

2023-05-18 Thread Rajnesh Kanwal
This change adds support for inserting virtual interrupts from M-mode
into S-mode using mvien and mvip csrs. IRQ filtering is a use case of
this change, i-e M-mode can stop delegating an interrupt to S-mode and
instead enable it in MIE and receive those interrupts in M-mode and then
selectively inject the interrupt using mvien and mvip.

Also, the spec doesn't mandate the interrupt to be actually supported
in hardware. Which allows M-mode to assert virtual interrupts to S-mode
that have no connection to any real interrupt events.

This is defined as part of the AIA specification [0], "5.3 Interrupt
filtering and virtual interrupts for supervisor level".

[0]: 
https://github.com/riscv/riscv-aia/releases/download/1.0-RC4/riscv-interrupts-1.0-RC4.pdf

Signed-off-by: Rajnesh Kanwal 
---
 target/riscv/cpu.c|   3 +-
 target/riscv/cpu.h|   8 ++
 target/riscv/cpu_bits.h   |   6 +
 target/riscv/cpu_helper.c |  26 +++-
 target/riscv/csr.c| 279 ++
 target/riscv/machine.c|   3 +
 6 files changed, 289 insertions(+), 36 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 90460cfe64..9557194a21 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -712,7 +712,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
  * Definition of the WFI instruction requires it to ignore the privilege
  * mode and delegation registers, but respect individual enables
  */
-return riscv_cpu_all_pending(env) != 0;
+return riscv_cpu_all_pending(env) != 0 ||
+riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
 #else
 return true;
 #endif
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index de55bfb775..07cf656471 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -190,6 +190,12 @@ struct CPUArchState {
 uint64_t mie;
 uint64_t mideleg;
 
+/*
+ * When mideleg[i]=0 and mvien[i]=1, sie[i] is no more
+ * alias of mie[i] and needs to be maintained separatly.
+ */
+uint64_t sie;
+
 target_ulong satp;   /* since: priv-1.10.0 */
 target_ulong stval;
 target_ulong medeleg;
@@ -210,6 +216,8 @@ struct CPUArchState {
 /* AIA CSRs */
 target_ulong miselect;
 target_ulong siselect;
+uint64_t mvien;
+uint64_t mvip;
 
 /* Hypervisor CSRs */
 target_ulong hstatus;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 59f0ffd9e1..0d32d2a5a7 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -735,6 +735,12 @@ typedef enum RISCVException {
 #define MIE_SSIE   (1 << IRQ_S_SOFT)
 #define MIE_USIE   (1 << IRQ_U_SOFT)
 
+/* Machine constants */
+#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
+#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
+#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
+#define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS))
+
 /* General PointerMasking CSR bits */
 #define PM_ENABLE   0x0001ULL
 #define PM_CURRENT  0x0002ULL
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 035437e0fb..681b4ae811 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -365,6 +365,10 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
 return best_irq;
 }
 
+/*
+ * Doesn't report interrupts inserted using mvip from M-mode firmware. Those
+ * are returned in riscv_cpu_sirq_pending().
+ */
 uint64_t riscv_cpu_all_pending(CPURISCVState *env)
 {
 uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -387,9 +391,10 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
 {
 uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
 ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+uint64_t irqs_f = env->mvip & env->mvien & ~env->mideleg & env->sie;
 
 return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-irqs, env->siprio);
+irqs | irqs_f, env->siprio);
 }
 
 int riscv_cpu_vsirq_pending(CPURISCVState *env)
@@ -403,8 +408,8 @@ int riscv_cpu_vsirq_pending(CPURISCVState *env)
 
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
+uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
 int virq;
-uint64_t irqs, pending, mie, hsie, vsie;
 
 /* Determine interrupt enable state of all privilege modes */
 if (env->virt_enabled) {
@@ -430,8 +435,11 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 irqs, env->miprio);
 }
 
+/* Check for virtual S-mode interrupts. */
+irqs_f = env->mvip & (env->mvien & ~env->mideleg) & env->sie;
+
 /* Check HS-mode interrupts */
-irqs = pending & env->mideleg & ~env->hideleg &

Re: [PATCH 1/1] target/riscv: Fix VS mode interrupts forwarding.

2020-02-26 Thread Rajnesh Kanwal
Here is the link to the patch
https://lists.nongnu.org/archive/html/qemu-riscv/2020-01/msg00191.html

-Rajnesh

On Tue, Feb 25, 2020 at 12:06 AM Alistair Francis 
wrote:

> On Sun, Feb 23, 2020 at 11:23 AM Jose Martins 
> wrote:
> >
> > Hello rajnesh,
> >
> > I had already submitted almost this exact patch a few weeks ago.
>
> To QEMU? I don't see the patch.
>
> Alistair
>
> >
> > Jose
> >
> > On Sun, 23 Feb 2020 at 13:51,  wrote:
> > >
> > > From: Rajnesh Kanwal 
> > >
> > > Currently riscv_cpu_local_irq_pending is used to find out pending
> > > interrupt and VS mode interrupts are being shifted to represent
> > > S mode interrupts in this function. So when the cause returned by
> > > this function is passed to riscv_cpu_do_interrupt to actually
> > > forward the interrupt, the VS mode forwarding check does not work
> > > as intended and interrupt is actually forwarded to hypervisor. This
> > > patch fixes this issue.
> > >
> > > Signed-off-by: Rajnesh Kanwal 
> > > ---
> > >  target/riscv/cpu_helper.c | 9 -
> > >  1 file changed, 8 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > > index b9e90dfd9a..59535ecba6 100644
> > > --- a/target/riscv/cpu_helper.c
> > > +++ b/target/riscv/cpu_helper.c
> > > @@ -46,7 +46,7 @@ static int riscv_cpu_local_irq_pending(CPURISCVState
> *env)
> > >  target_ulong pending = env->mip & env->mie &
> > > ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > >  target_ulong vspending = (env->mip & env->mie &
> > > -  (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) >>
> 1;
> > > +  (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> > >
> > >  target_ulong mie= env->priv < PRV_M ||
> > >(env->priv == PRV_M && mstatus_mie);
> > > @@ -900,6 +900,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> > >
> > >  if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) &
> 1) &&
> > >  !force_hs_execp) {
> > > +/*
> > > + * See if we need to adjust cause. Yes if its VS mode
> interrupt
> > > + * no if hypervisor has delegated one of hs mode's
> interrupt
> > > + */
> > > +if (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
> > > +cause == IRQ_VS_EXT)
> > > +cause = cause - 1;
> > >  /* Trap to VS mode */
> > >  } else if (riscv_cpu_virt_enabled(env)) {
> > >  /* Trap into HS mode, from virt */
> > > --
> > > 2.17.1
> > >
> > >
> >
>


Re: [PATCH 1/1] target/riscv: Fix VS mode interrupts forwarding.

2020-02-24 Thread Rajnesh Kanwal
Nice catch. You are right. I was a bit confused after looking at current
xvisor and KVM port. They are delegating S mode interrupts to VS mode, as
per my understanding after looking at
https://github.com/kvm-riscv/linux/blob/riscv_kvm_master/arch/riscv/kvm/main.c
line no. 34. I will see if there is a way to decline a patch.

Thanks for pointing that out.
Regards,
Rajnesh

On Sun, Feb 23, 2020 at 8:40 PM Jose Martins 
wrote:

> No problem. But I'm failing to see what you mean. My reasoning was:
> the specification mandates that only VS mode interrupt bits are
> writable in hideleg, all the others must be hardwired to zero. This
> means the hypervisor can't really delegate S mode interrupts as you
> are saying. So, if this is implemented correctly, you will never get
> inside that if condition because of an HS interrupt. And all
> delegatable asynchronous exception values must be decremented. So,
> checking if this is an async exception should do the job.
>
> Jose
>
> On Sun, 23 Feb 2020 at 15:10, Rajnesh Kanwal 
> wrote:
> >
> > Hello Jose,
> >
> > Sorry I didn't see that as it hadn't became a part of the port. I don't
> know how
> > they proceed with same patches.
> >
> > Just to add, there is a minor problem with your patch. The cause value
> should
> > only be decremented by one for VS mode interrupts. In case if hypervisor
> has
> > delegated S mode interrupts then we should not decrement cause for those
> > interrupts.
> >
> > Regards,
> > Rajnesh
> >
> >
> > On Sun, Feb 23, 2020 at 7:41 PM Jose Martins 
> wrote:
> >>
> >> Hello rajnesh,
> >>
> >> I had already submitted almost this exact patch a few weeks ago.
> >>
> >> Jose
> >>
> >> On Sun, 23 Feb 2020 at 13:51,  wrote:
> >> >
> >> > From: Rajnesh Kanwal 
> >> >
> >> > Currently riscv_cpu_local_irq_pending is used to find out pending
> >> > interrupt and VS mode interrupts are being shifted to represent
> >> > S mode interrupts in this function. So when the cause returned by
> >> > this function is passed to riscv_cpu_do_interrupt to actually
> >> > forward the interrupt, the VS mode forwarding check does not work
> >> > as intended and interrupt is actually forwarded to hypervisor. This
> >> > patch fixes this issue.
> >> >
> >> > Signed-off-by: Rajnesh Kanwal 
> >> > ---
> >> >  target/riscv/cpu_helper.c | 9 -
> >> >  1 file changed, 8 insertions(+), 1 deletion(-)
> >> >
> >> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> >> > index b9e90dfd9a..59535ecba6 100644
> >> > --- a/target/riscv/cpu_helper.c
> >> > +++ b/target/riscv/cpu_helper.c
> >> > @@ -46,7 +46,7 @@ static int
> riscv_cpu_local_irq_pending(CPURISCVState *env)
> >> >  target_ulong pending = env->mip & env->mie &
> >> > ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> >> >  target_ulong vspending = (env->mip & env->mie &
> >> > -  (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> >> 1;
> >> > +  (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> >> >
> >> >  target_ulong mie= env->priv < PRV_M ||
> >> >(env->priv == PRV_M && mstatus_mie);
> >> > @@ -900,6 +900,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> >> >
> >> >  if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) &
> 1) &&
> >> >  !force_hs_execp) {
> >> > +/*
> >> > + * See if we need to adjust cause. Yes if its VS
> mode interrupt
> >> > + * no if hypervisor has delegated one of hs mode's
> interrupt
> >> > + */
> >> > +if (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
> >> > +cause == IRQ_VS_EXT)
> >> > +cause = cause - 1;
> >> >  /* Trap to VS mode */
> >> >  } else if (riscv_cpu_virt_enabled(env)) {
> >> >  /* Trap into HS mode, from virt */
> >> > --
> >> > 2.17.1
> >> >
> >> >
>


Re: [PATCH 1/1] target/riscv: Fix VS mode interrupts forwarding.

2020-02-23 Thread Rajnesh Kanwal
Hello Jose,

Sorry I didn't see that as it hadn't became a part of the port. I don't
know how
they proceed with same patches.

Just to add, there is a minor problem with your patch. The cause value
should
only be decremented by one for VS mode interrupts. In case if hypervisor has
delegated S mode interrupts then we should not decrement cause for those
interrupts.

Regards,
Rajnesh


On Sun, Feb 23, 2020 at 7:41 PM Jose Martins 
wrote:

> Hello rajnesh,
>
> I had already submitted almost this exact patch a few weeks ago.
>
> Jose
>
> On Sun, 23 Feb 2020 at 13:51,  wrote:
> >
> > From: Rajnesh Kanwal 
> >
> > Currently riscv_cpu_local_irq_pending is used to find out pending
> > interrupt and VS mode interrupts are being shifted to represent
> > S mode interrupts in this function. So when the cause returned by
> > this function is passed to riscv_cpu_do_interrupt to actually
> > forward the interrupt, the VS mode forwarding check does not work
> > as intended and interrupt is actually forwarded to hypervisor. This
> > patch fixes this issue.
> >
> > Signed-off-by: Rajnesh Kanwal 
> > ---
> >  target/riscv/cpu_helper.c | 9 -
> >  1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index b9e90dfd9a..59535ecba6 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -46,7 +46,7 @@ static int riscv_cpu_local_irq_pending(CPURISCVState
> *env)
> >  target_ulong pending = env->mip & env->mie &
> > ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> >  target_ulong vspending = (env->mip & env->mie &
> > -  (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) >> 1;
> > +  (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> >
> >  target_ulong mie= env->priv < PRV_M ||
> >(env->priv == PRV_M && mstatus_mie);
> > @@ -900,6 +900,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> >
> >  if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1)
> &&
> >  !force_hs_execp) {
> > +/*
> > + * See if we need to adjust cause. Yes if its VS mode
> interrupt
> > + * no if hypervisor has delegated one of hs mode's
> interrupt
> > + */
> > +if (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
> > +cause == IRQ_VS_EXT)
> > +cause = cause - 1;
> >  /* Trap to VS mode */
> >  } else if (riscv_cpu_virt_enabled(env)) {
> >  /* Trap into HS mode, from virt */
> > --
> > 2.17.1
> >
> >
>