[PATCH v3] target/riscv: Restore LCOFI handling in interrupt CSRs

Mayuresh Chitale posted 1 patch 5 days, 4 hours ago
target/riscv/tcg/csr.c | 88 +++++++++++++++++++++++++++++++++++-------
1 file changed, 73 insertions(+), 15 deletions(-)
[PATCH v3] target/riscv: Restore LCOFI handling in interrupt CSRs
Posted by Mayuresh Chitale 5 days, 4 hours ago
Commit 27f9566dcd98 dropped bits 13-15 from the LOCAL_INTERRUPTS
macro and hence also from individual masks such as all_ints,
sip_writable_mask etc.

As a result, even with sscofpmf and ssaia enabled, the LCOFI never got
delivered to the host OS and guest OS respectively.

Add back bit 13 in all the affected masks, but gate it on Sscofpmf being
implemented. For the virtual interrupt paths, i.e., mvip/mvien,
hvip/hvien/vsip/vsie registers, bit 13 is additionally gated on Smaia
and Ssaia respectively. Bits 14, 15 can be added when those interrupt
sources get defined.

Fixes: 27f9566dcd98 ("target/riscv: Update the local interrupt mask")
Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com>
Suggested-by: Gong Shuai <gsh517025@gmail.com>
Suggested-by: TianCheng TANG <lyndra@linux.alibaba.com>
Signed-off-by: Mayuresh Chitale <mayuresh.chitale@oss.qualcomm.com>
---
 target/riscv/tcg/csr.c | 88 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 73 insertions(+), 15 deletions(-)

diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
index 061bc9db77..a3351428cb 100644
--- a/target/riscv/tcg/csr.c
+++ b/target/riscv/tcg/csr.c
@@ -1815,7 +1815,7 @@ static RISCVException write_stimecmph(CPURISCVState *env, int csrno,
 #define LOCAL_INTERRUPTS   (~0xFFFFULL)
 
 static const uint64_t delegable_ints =
-    S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS | MIP_LCOFIP;
+    S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS;
 static const uint64_t vs_delegable_ints =
     (VS_MODE_INTERRUPTS | LOCAL_INTERRUPTS) & ~MIP_LCOFIP;
 static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
@@ -1877,6 +1877,42 @@ static const uint64_t hvien_writable_mask = LOCAL_INTERRUPTS;
 
 static const uint64_t vsip_writable_mask = MIP_VSSIP | LOCAL_INTERRUPTS;
 
+/*
+ * Selects the extensions that need to be checked when accessing various
+ * interrupt registers.
+ */
+typedef enum {
+    /* Accessing mideleg, mie, mip, and alias paths  */
+    AIA_NONE,
+    /* Accessing mvien, mvip non-alias path */
+    AIA_SMAIA,
+    /* Accessing hvien, hvip, vsie, vsip paths */
+    AIA_SSAIA,
+} AIAExt;
+
+/*
+ * This function can be extended later to configure mask for standard local
+ * interrupt bits 14 and 15, once those get defined in the Priv Spec.
+ */
+static uint64_t std_impl_intr_mask(CPURISCVState *env, AIAExt ext)
+{
+    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
+
+    if (ext == AIA_SMAIA && !cfg->ext_smaia) {
+        return 0;
+    }
+
+    if (ext == AIA_SSAIA && !cfg->ext_ssaia) {
+        return 0;
+    }
+
+    if (!cfg->ext_sscofpmf) {
+        return 0;
+    }
+
+    return MIP_LCOFIP;
+}
+
 /* Machine Information Registers */
 static RISCVException read_zero(CPURISCVState *env, int csrno,
                                 target_ulong *val)
@@ -2249,8 +2285,10 @@ static RISCVException rmw_mideleg64(CPURISCVState *env, int csrno,
                                     uint64_t *ret_val,
                                     uint64_t new_val, uint64_t wr_mask)
 {
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
     uint64_t mask = wr_mask & delegable_ints;
 
+    mask |= wr_mask & std_mask;
     if (ret_val) {
         *ret_val = env->mideleg;
     }
@@ -2300,8 +2338,10 @@ static RISCVException rmw_mie64(CPURISCVState *env, int csrno,
                                 uint64_t *ret_val,
                                 uint64_t new_val, uint64_t wr_mask)
 {
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
     uint64_t mask = wr_mask & all_ints;
 
+    mask |= wr_mask & std_mask;
     if (ret_val) {
         *ret_val = env->mie;
     }
@@ -2350,8 +2390,10 @@ static RISCVException rmw_mvien64(CPURISCVState *env, int csrno,
                                 uint64_t *ret_val,
                                 uint64_t new_val, uint64_t wr_mask)
 {
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_SMAIA);
     uint64_t mask = wr_mask & mvien_writable_mask;
 
+    mask |= wr_mask & std_mask;
     if (ret_val) {
         *ret_val = env->mvien;
     }
@@ -3784,9 +3826,12 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
                                 uint64_t *ret_val,
                                 uint64_t new_val, uint64_t wr_mask)
 {
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
     uint64_t old_mip, mask = wr_mask & delegable_ints;
     uint32_t gin;
 
+    mask |= wr_mask & std_mask;
+
     /*
      * When mvien[9]=1, mip.SEIP is read-only and reflects only
      * the external interrupt signal from the interrupt controller.
@@ -3900,9 +3945,12 @@ static RISCVException rmw_mvip64(CPURISCVState *env, int csrno,
      *  alias_mask denotes the bits that come from mip nalias_mask denotes bits
      *  that come from hvip.
      */
-    uint64_t alias_mask = ((S_MODE_INTERRUPTS | LOCAL_INTERRUPTS) &
+    AIAExt intr_virt = ((csrno == CSR_MVIP) || (csrno == CSR_MVIPH)) ?
+                          AIA_SMAIA : AIA_NONE;
+    uint64_t std_mask = std_impl_intr_mask(env, intr_virt);
+    uint64_t alias_mask = ((S_MODE_INTERRUPTS | std_mask | LOCAL_INTERRUPTS) &
         (env->mideleg | ~env->mvien)) | MIP_STIP;
-    uint64_t nalias_mask = (S_MODE_INTERRUPTS | LOCAL_INTERRUPTS) &
+    uint64_t nalias_mask = (S_MODE_INTERRUPTS | std_mask | LOCAL_INTERRUPTS) &
         (~env->mideleg & env->mvien);
     uint64_t wr_mask_mvip;
     uint64_t wr_mask_mip;
@@ -3931,8 +3979,8 @@ static RISCVException rmw_mvip64(CPURISCVState *env, int csrno,
         alias_mask &= ~MIP_STIP;
     }
 
-    wr_mask_mip = wr_mask & alias_mask & mvip_writable_mask;
-    wr_mask_mvip = wr_mask & nalias_mask & mvip_writable_mask;
+    wr_mask_mip = wr_mask & alias_mask & (mvip_writable_mask | std_mask);
+    wr_mask_mvip = wr_mask & nalias_mask & (mvip_writable_mask | std_mask);
 
     /*
      * For bits set in alias_mask, mvip needs to be alias of mip, so forward
@@ -4065,9 +4113,11 @@ static RISCVException rmw_vsie64(CPURISCVState *env, int csrno,
                                  uint64_t *ret_val,
                                  uint64_t new_val, uint64_t wr_mask)
 {
-    uint64_t alias_mask = (LOCAL_INTERRUPTS | VS_MODE_INTERRUPTS) &
-                            env->hideleg;
-    uint64_t nalias_mask = LOCAL_INTERRUPTS & (~env->hideleg & env->hvien);
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_SSAIA);
+    uint64_t alias_mask = (LOCAL_INTERRUPTS | VS_MODE_INTERRUPTS |
+                           std_mask) & env->hideleg;
+    uint64_t nalias_mask = (LOCAL_INTERRUPTS | std_mask) &
+                           (~env->hideleg & env->hvien);
     uint64_t rval, rval_vs, vsbits;
     uint64_t wr_mask_vsie;
     uint64_t wr_mask_mie;
@@ -4135,9 +4185,11 @@ static RISCVException rmw_sie64(CPURISCVState *env, int csrno,
                                 uint64_t *ret_val,
                                 uint64_t new_val, uint64_t wr_mask)
 {
-    uint64_t nalias_mask = (S_MODE_INTERRUPTS | LOCAL_INTERRUPTS) &
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
+    uint64_t nalias_mask = (S_MODE_INTERRUPTS | std_mask | LOCAL_INTERRUPTS) &
         (~env->mideleg & env->mvien);
-    uint64_t alias_mask = (S_MODE_INTERRUPTS | LOCAL_INTERRUPTS) & env->mideleg;
+    uint64_t alias_mask = (S_MODE_INTERRUPTS | std_mask | LOCAL_INTERRUPTS) &
+        env->mideleg;
     uint64_t sie_mask = wr_mask & nalias_mask;
     RISCVException ret;
 
@@ -4320,6 +4372,7 @@ static RISCVException rmw_vsip64(CPURISCVState *env, int csrno,
                                  uint64_t new_val, uint64_t wr_mask)
 {
     RISCVException ret;
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_SSAIA);
     uint64_t rval, mask = env->hideleg & VS_MODE_INTERRUPTS;
     uint64_t vsbits;
 
@@ -4335,7 +4388,7 @@ static RISCVException rmw_vsip64(CPURISCVState *env, int csrno,
     wr_mask |= vsbits << 1;
 
     ret = rmw_hvip64(env, csrno, &rval, new_val,
-                     wr_mask & mask & vsip_writable_mask);
+                     wr_mask & mask & (vsip_writable_mask | std_mask));
     if (ret_val) {
         rval &= mask;
         vsbits = rval & VS_MODE_INTERRUPTS;
@@ -4382,7 +4435,9 @@ static RISCVException rmw_sip64(CPURISCVState *env, int csrno,
                                 uint64_t new_val, uint64_t wr_mask)
 {
     RISCVException ret;
-    uint64_t mask = (env->mideleg | env->mvien) & sip_writable_mask;
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
+    uint64_t mask = (env->mideleg | env->mvien) &
+                    (sip_writable_mask | std_mask);
 
     if (env->virt_enabled) {
         if (env->hvictl & HVICTL_VTI) {
@@ -4395,7 +4450,7 @@ static RISCVException rmw_sip64(CPURISCVState *env, int csrno,
 
     if (ret_val) {
         *ret_val &= (env->mideleg | env->mvien) &
-            (S_MODE_INTERRUPTS | LOCAL_INTERRUPTS);
+            (S_MODE_INTERRUPTS | std_mask | LOCAL_INTERRUPTS);
     }
 
     return ret;
@@ -4737,7 +4792,9 @@ static RISCVException rmw_hvien64(CPURISCVState *env, int csrno,
                                     uint64_t new_val, uint64_t wr_mask)
 {
     uint64_t mask = wr_mask & hvien_writable_mask;
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_SSAIA);
 
+    mask |= wr_mask & std_mask;
     if (ret_val) {
         *ret_val = env->hvien;
     }
@@ -4861,6 +4918,7 @@ static RISCVException rmw_hvip64(CPURISCVState *env, int csrno,
      */
     uint64_t alias_mask = (env->hideleg | ~env->hvien) | VS_MODE_INTERRUPTS;
     uint64_t nalias_mask = (~env->hideleg & env->hvien);
+    uint64_t std_mask = std_impl_intr_mask(env, AIA_SSAIA);
     uint64_t wr_mask_hvip;
     uint64_t wr_mask_mip;
 
@@ -4882,8 +4940,8 @@ static RISCVException rmw_hvip64(CPURISCVState *env, int csrno,
         alias_mask &= (env->hideleg | env->hvien);
     }
 
-    wr_mask_hvip = wr_mask & nalias_mask & hvip_writable_mask;
-    wr_mask_mip = wr_mask & alias_mask & hvip_writable_mask;
+    wr_mask_hvip = wr_mask & nalias_mask & (hvip_writable_mask | std_mask);
+    wr_mask_mip = wr_mask & alias_mask & (hvip_writable_mask | std_mask);
 
     /* Aliased bits, bits 10, 6, 2 need to come from mip. */
     ret = rmw_mip64(env, csrno, &ret_mip, new_val, wr_mask_mip);
-- 
2.43.0
Re: [PATCH v3] target/riscv: Restore LCOFI handling in interrupt CSRs
Posted by Alistair Francis 4 days, 18 hours ago
On Mon, 2026-09-21 at 20:23 +0530, Mayuresh Chitale wrote:
> Commit 27f9566dcd98 dropped bits 13-15 from the LOCAL_INTERRUPTS
> macro and hence also from individual masks such as all_ints,
> sip_writable_mask etc.
> 
> As a result, even with sscofpmf and ssaia enabled, the LCOFI never
> got
> delivered to the host OS and guest OS respectively.
> 
> Add back bit 13 in all the affected masks, but gate it on Sscofpmf
> being
> implemented. For the virtual interrupt paths, i.e., mvip/mvien,
> hvip/hvien/vsip/vsie registers, bit 13 is additionally gated on Smaia
> and Ssaia respectively. Bits 14, 15 can be added when those interrupt
> sources get defined.
> 
> Fixes: 27f9566dcd98 ("target/riscv: Update the local interrupt mask")
> Reviewed-by: Daniel Henrique Barboza
> <daniel.barboza@oss.qualcomm.com>
> Suggested-by: Gong Shuai <gsh517025@gmail.com>
> Suggested-by: TianCheng TANG <lyndra@linux.alibaba.com>
> Signed-off-by: Mayuresh Chitale <mayuresh.chitale@oss.qualcomm.com>

Thanks!

Applied to riscv-to-apply.next

Alistair

> ---
>  target/riscv/tcg/csr.c | 88 +++++++++++++++++++++++++++++++++++-----
> --
>  1 file changed, 73 insertions(+), 15 deletions(-)
> 
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index 061bc9db77..a3351428cb 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -1815,7 +1815,7 @@ static RISCVException
> write_stimecmph(CPURISCVState *env, int csrno,
>  #define LOCAL_INTERRUPTS   (~0xFFFFULL)
>  
>  static const uint64_t delegable_ints =
> -    S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS | MIP_LCOFIP;
> +    S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS;
>  static const uint64_t vs_delegable_ints =
>      (VS_MODE_INTERRUPTS | LOCAL_INTERRUPTS) & ~MIP_LCOFIP;
>  static const uint64_t all_ints = M_MODE_INTERRUPTS |
> S_MODE_INTERRUPTS |
> @@ -1877,6 +1877,42 @@ static const uint64_t hvien_writable_mask =
> LOCAL_INTERRUPTS;
>  
>  static const uint64_t vsip_writable_mask = MIP_VSSIP |
> LOCAL_INTERRUPTS;
>  
> +/*
> + * Selects the extensions that need to be checked when accessing
> various
> + * interrupt registers.
> + */
> +typedef enum {
> +    /* Accessing mideleg, mie, mip, and alias paths  */
> +    AIA_NONE,
> +    /* Accessing mvien, mvip non-alias path */
> +    AIA_SMAIA,
> +    /* Accessing hvien, hvip, vsie, vsip paths */
> +    AIA_SSAIA,
> +} AIAExt;
> +
> +/*
> + * This function can be extended later to configure mask for
> standard local
> + * interrupt bits 14 and 15, once those get defined in the Priv
> Spec.
> + */
> +static uint64_t std_impl_intr_mask(CPURISCVState *env, AIAExt ext)
> +{
> +    const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
> +
> +    if (ext == AIA_SMAIA && !cfg->ext_smaia) {
> +        return 0;
> +    }
> +
> +    if (ext == AIA_SSAIA && !cfg->ext_ssaia) {
> +        return 0;
> +    }
> +
> +    if (!cfg->ext_sscofpmf) {
> +        return 0;
> +    }
> +
> +    return MIP_LCOFIP;
> +}
> +
>  /* Machine Information Registers */
>  static RISCVException read_zero(CPURISCVState *env, int csrno,
>                                  target_ulong *val)
> @@ -2249,8 +2285,10 @@ static RISCVException
> rmw_mideleg64(CPURISCVState *env, int csrno,
>                                      uint64_t *ret_val,
>                                      uint64_t new_val, uint64_t
> wr_mask)
>  {
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
>      uint64_t mask = wr_mask & delegable_ints;
>  
> +    mask |= wr_mask & std_mask;
>      if (ret_val) {
>          *ret_val = env->mideleg;
>      }
> @@ -2300,8 +2338,10 @@ static RISCVException rmw_mie64(CPURISCVState
> *env, int csrno,
>                                  uint64_t *ret_val,
>                                  uint64_t new_val, uint64_t wr_mask)
>  {
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
>      uint64_t mask = wr_mask & all_ints;
>  
> +    mask |= wr_mask & std_mask;
>      if (ret_val) {
>          *ret_val = env->mie;
>      }
> @@ -2350,8 +2390,10 @@ static RISCVException
> rmw_mvien64(CPURISCVState *env, int csrno,
>                                  uint64_t *ret_val,
>                                  uint64_t new_val, uint64_t wr_mask)
>  {
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_SMAIA);
>      uint64_t mask = wr_mask & mvien_writable_mask;
>  
> +    mask |= wr_mask & std_mask;
>      if (ret_val) {
>          *ret_val = env->mvien;
>      }
> @@ -3784,9 +3826,12 @@ static RISCVException rmw_mip64(CPURISCVState
> *env, int csrno,
>                                  uint64_t *ret_val,
>                                  uint64_t new_val, uint64_t wr_mask)
>  {
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
>      uint64_t old_mip, mask = wr_mask & delegable_ints;
>      uint32_t gin;
>  
> +    mask |= wr_mask & std_mask;
> +
>      /*
>       * When mvien[9]=1, mip.SEIP is read-only and reflects only
>       * the external interrupt signal from the interrupt controller.
> @@ -3900,9 +3945,12 @@ static RISCVException rmw_mvip64(CPURISCVState
> *env, int csrno,
>       *  alias_mask denotes the bits that come from mip nalias_mask
> denotes bits
>       *  that come from hvip.
>       */
> -    uint64_t alias_mask = ((S_MODE_INTERRUPTS | LOCAL_INTERRUPTS) &
> +    AIAExt intr_virt = ((csrno == CSR_MVIP) || (csrno == CSR_MVIPH))
> ?
> +                          AIA_SMAIA : AIA_NONE;
> +    uint64_t std_mask = std_impl_intr_mask(env, intr_virt);
> +    uint64_t alias_mask = ((S_MODE_INTERRUPTS | std_mask |
> LOCAL_INTERRUPTS) &
>          (env->mideleg | ~env->mvien)) | MIP_STIP;
> -    uint64_t nalias_mask = (S_MODE_INTERRUPTS | LOCAL_INTERRUPTS) &
> +    uint64_t nalias_mask = (S_MODE_INTERRUPTS | std_mask |
> LOCAL_INTERRUPTS) &
>          (~env->mideleg & env->mvien);
>      uint64_t wr_mask_mvip;
>      uint64_t wr_mask_mip;
> @@ -3931,8 +3979,8 @@ static RISCVException rmw_mvip64(CPURISCVState
> *env, int csrno,
>          alias_mask &= ~MIP_STIP;
>      }
>  
> -    wr_mask_mip = wr_mask & alias_mask & mvip_writable_mask;
> -    wr_mask_mvip = wr_mask & nalias_mask & mvip_writable_mask;
> +    wr_mask_mip = wr_mask & alias_mask & (mvip_writable_mask |
> std_mask);
> +    wr_mask_mvip = wr_mask & nalias_mask & (mvip_writable_mask |
> std_mask);
>  
>      /*
>       * For bits set in alias_mask, mvip needs to be alias of mip, so
> forward
> @@ -4065,9 +4113,11 @@ static RISCVException rmw_vsie64(CPURISCVState
> *env, int csrno,
>                                   uint64_t *ret_val,
>                                   uint64_t new_val, uint64_t wr_mask)
>  {
> -    uint64_t alias_mask = (LOCAL_INTERRUPTS | VS_MODE_INTERRUPTS) &
> -                            env->hideleg;
> -    uint64_t nalias_mask = LOCAL_INTERRUPTS & (~env->hideleg & env-
> >hvien);
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_SSAIA);
> +    uint64_t alias_mask = (LOCAL_INTERRUPTS | VS_MODE_INTERRUPTS |
> +                           std_mask) & env->hideleg;
> +    uint64_t nalias_mask = (LOCAL_INTERRUPTS | std_mask) &
> +                           (~env->hideleg & env->hvien);
>      uint64_t rval, rval_vs, vsbits;
>      uint64_t wr_mask_vsie;
>      uint64_t wr_mask_mie;
> @@ -4135,9 +4185,11 @@ static RISCVException rmw_sie64(CPURISCVState
> *env, int csrno,
>                                  uint64_t *ret_val,
>                                  uint64_t new_val, uint64_t wr_mask)
>  {
> -    uint64_t nalias_mask = (S_MODE_INTERRUPTS | LOCAL_INTERRUPTS) &
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
> +    uint64_t nalias_mask = (S_MODE_INTERRUPTS | std_mask |
> LOCAL_INTERRUPTS) &
>          (~env->mideleg & env->mvien);
> -    uint64_t alias_mask = (S_MODE_INTERRUPTS | LOCAL_INTERRUPTS) &
> env->mideleg;
> +    uint64_t alias_mask = (S_MODE_INTERRUPTS | std_mask |
> LOCAL_INTERRUPTS) &
> +        env->mideleg;
>      uint64_t sie_mask = wr_mask & nalias_mask;
>      RISCVException ret;
>  
> @@ -4320,6 +4372,7 @@ static RISCVException rmw_vsip64(CPURISCVState
> *env, int csrno,
>                                   uint64_t new_val, uint64_t wr_mask)
>  {
>      RISCVException ret;
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_SSAIA);
>      uint64_t rval, mask = env->hideleg & VS_MODE_INTERRUPTS;
>      uint64_t vsbits;
>  
> @@ -4335,7 +4388,7 @@ static RISCVException rmw_vsip64(CPURISCVState
> *env, int csrno,
>      wr_mask |= vsbits << 1;
>  
>      ret = rmw_hvip64(env, csrno, &rval, new_val,
> -                     wr_mask & mask & vsip_writable_mask);
> +                     wr_mask & mask & (vsip_writable_mask |
> std_mask));
>      if (ret_val) {
>          rval &= mask;
>          vsbits = rval & VS_MODE_INTERRUPTS;
> @@ -4382,7 +4435,9 @@ static RISCVException rmw_sip64(CPURISCVState
> *env, int csrno,
>                                  uint64_t new_val, uint64_t wr_mask)
>  {
>      RISCVException ret;
> -    uint64_t mask = (env->mideleg | env->mvien) & sip_writable_mask;
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_NONE);
> +    uint64_t mask = (env->mideleg | env->mvien) &
> +                    (sip_writable_mask | std_mask);
>  
>      if (env->virt_enabled) {
>          if (env->hvictl & HVICTL_VTI) {
> @@ -4395,7 +4450,7 @@ static RISCVException rmw_sip64(CPURISCVState
> *env, int csrno,
>  
>      if (ret_val) {
>          *ret_val &= (env->mideleg | env->mvien) &
> -            (S_MODE_INTERRUPTS | LOCAL_INTERRUPTS);
> +            (S_MODE_INTERRUPTS | std_mask | LOCAL_INTERRUPTS);
>      }
>  
>      return ret;
> @@ -4737,7 +4792,9 @@ static RISCVException rmw_hvien64(CPURISCVState
> *env, int csrno,
>                                      uint64_t new_val, uint64_t
> wr_mask)
>  {
>      uint64_t mask = wr_mask & hvien_writable_mask;
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_SSAIA);
>  
> +    mask |= wr_mask & std_mask;
>      if (ret_val) {
>          *ret_val = env->hvien;
>      }
> @@ -4861,6 +4918,7 @@ static RISCVException rmw_hvip64(CPURISCVState
> *env, int csrno,
>       */
>      uint64_t alias_mask = (env->hideleg | ~env->hvien) |
> VS_MODE_INTERRUPTS;
>      uint64_t nalias_mask = (~env->hideleg & env->hvien);
> +    uint64_t std_mask = std_impl_intr_mask(env, AIA_SSAIA);
>      uint64_t wr_mask_hvip;
>      uint64_t wr_mask_mip;
>  
> @@ -4882,8 +4940,8 @@ static RISCVException rmw_hvip64(CPURISCVState
> *env, int csrno,
>          alias_mask &= (env->hideleg | env->hvien);
>      }
>  
> -    wr_mask_hvip = wr_mask & nalias_mask & hvip_writable_mask;
> -    wr_mask_mip = wr_mask & alias_mask & hvip_writable_mask;
> +    wr_mask_hvip = wr_mask & nalias_mask & (hvip_writable_mask |
> std_mask);
> +    wr_mask_mip = wr_mask & alias_mask & (hvip_writable_mask |
> std_mask);
>  
>      /* Aliased bits, bits 10, 6, 2 need to come from mip. */
>      ret = rmw_mip64(env, csrno, &ret_mip, new_val, wr_mask_mip);