On Fri, Jul 4, 2025 at 4:25 AM Charalampos Mitrodimas
<charmi...@posteo.net> wrote:
>
> According to the RISC-V Privileged Architecture specification, the low
> bit of MEPC/SEPC must always be zero. When IALIGN=32, the two low bits
> must be zero.
>
> This commit fixes the behavior of MEPC/SEPC CSR reads and writes, and
> the implicit reads by MRET/SRET instructions to properly mask the
> lowest bit(s) based on whether the C extension is enabled:
> - When C extension is enabled (IALIGN=16): mask bit 0
> - When C extension is disabled (IALIGN=32): mask bits [1:0]
>
> Previously, when vectored mode bits from STVEC (which sets bit 0 for
> vectored mode) were written to MEPC, the bits would not be cleared
> correctly, causing incorrect behavior on MRET.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2855
> Signed-off-by: Charalampos Mitrodimas <charmi...@posteo.net>

Reviewed-by: Alistair Francis <alistair.fran...@wdc.com>

Alistair

> ---
>  target/riscv/csr.c       |  8 ++++----
>  target/riscv/internals.h | 11 +++++++++++
>  target/riscv/op_helper.c |  4 ++--
>  3 files changed, 17 insertions(+), 6 deletions(-)
>
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index fb14972169..c33a6e86d2 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -3126,14 +3126,14 @@ static RISCVException write_mscratch(CPURISCVState 
> *env, int csrno,
>  static RISCVException read_mepc(CPURISCVState *env, int csrno,
>                                  target_ulong *val)
>  {
> -    *val = env->mepc;
> +    *val = env->mepc & get_xepc_mask(env);
>      return RISCV_EXCP_NONE;
>  }
>
>  static RISCVException write_mepc(CPURISCVState *env, int csrno,
>                                   target_ulong val, uintptr_t ra)
>  {
> -    env->mepc = val;
> +    env->mepc = val & get_xepc_mask(env);
>      return RISCV_EXCP_NONE;
>  }
>
> @@ -4113,14 +4113,14 @@ static RISCVException write_sscratch(CPURISCVState 
> *env, int csrno,
>  static RISCVException read_sepc(CPURISCVState *env, int csrno,
>                                  target_ulong *val)
>  {
> -    *val = env->sepc;
> +    *val = env->sepc & get_xepc_mask(env);
>      return RISCV_EXCP_NONE;
>  }
>
>  static RISCVException write_sepc(CPURISCVState *env, int csrno,
>                                   target_ulong val, uintptr_t ra)
>  {
> -    env->sepc = val;
> +    env->sepc = val & get_xepc_mask(env);
>      return RISCV_EXCP_NONE;
>  }
>
> diff --git a/target/riscv/internals.h b/target/riscv/internals.h
> index 4570bd50be..89ac6a160f 100644
> --- a/target/riscv/internals.h
> +++ b/target/riscv/internals.h
> @@ -142,6 +142,17 @@ static inline float16 check_nanbox_h(CPURISCVState *env, 
> uint64_t f)
>      }
>  }
>
> +static inline target_ulong get_xepc_mask(CPURISCVState *env)
> +{
> +    /* When IALIGN=32, both low bits must be zero.
> +     * When IALIGN=16 (has C extension), only bit 0 must be zero. */
> +    if (riscv_has_ext(env, RVC)) {
> +        return ~(target_ulong)1;
> +    } else {
> +        return ~(target_ulong)3;
> +    }
> +}
> +
>  #ifndef CONFIG_USER_ONLY
>  /* Our implementation of SysemuCPUOps::has_work */
>  bool riscv_cpu_has_work(CPUState *cs);
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index 557807ba4b..15460bf84b 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -280,7 +280,7 @@ target_ulong helper_sret(CPURISCVState *env)
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      }
>
> -    target_ulong retpc = env->sepc;
> +    target_ulong retpc = env->sepc & get_xepc_mask(env);
>      if (!riscv_cpu_allow_16bit_insn(&env_archcpu(env)->cfg,
>                                      env->priv_ver,
>                                      env->misa_ext) && (retpc & 0x3)) {
> @@ -391,7 +391,7 @@ static target_ulong ssdbltrp_mxret(CPURISCVState *env, 
> target_ulong mstatus,
>
>  target_ulong helper_mret(CPURISCVState *env)
>  {
> -    target_ulong retpc = env->mepc;
> +    target_ulong retpc = env->mepc & get_xepc_mask(env);
>      uint64_t mstatus = env->mstatus;
>      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
>
> --
> 2.47.2
>
>

Reply via email to