[PATCH v2 7/8] lib: sbi: Rework load/store emulator instruction decoding

Anup Patel apatel at ventanamicro.com
Tue Jun 16 01:21:33 PDT 2026


On Fri, Jun 5, 2026 at 8:22 PM Bo Gan <ganboing at gmail.com> wrote:
>
> Rehaul instruction decoding to fix the following issues:
>
> - We assume the XLEN of previous mode is the same as MXLEN. However,
>   RVC instructions decodes differently in RV32 and RV64, so shouldn't
>   have assumed that.
> - We assume it's a misaligned fault and the load/store offset is 0,
>   i.e., base address == fault address, but access faults can have
>   non-0 offset (on HW supporting misaligned accesses), so platform
>   specific load/store fault handler gets the wrong base address.
> - No checking of [63:32] of tinst in RV64, which is explicitly
>   required by Privileged ISA 19.6.3. Must reject tinst with non-0
>   high 32 bits.
>
> Thus, fix all the above. For misaligned load/store fault, the address
> offset should be 0, but we'll validate that on a DEBUG build. On an
> optmized build, we kill the use of base address, and use trap address
> instead (same as before), which lets the compiler optimize out imm
> parsing and other calculations.
>
> I also analyzed the behavior of misaligned fault handler before fix.
> With the following conditions met, it can trigger data corruption:
>
> - HW doesn't transform instruction into tinst.
> - HW doesn't support misaligned load/store, and OS doesn't enable
>   misaligned delegation, thus OpenSBI handler is in effect
> - HW supports mixed XLEN, and M mode is running RV64, and the trapping
>   mode (U/VS/VU) is running RV32.
> - The trapping instruction is c.f{l|s}w(sp).
>
> Due to the incorrect insn decoding, the trapping instruction would
> mistakenly be decoded as c.{l|s}d(sp). With this fix, c.f{l|s}w(sp)
> in RV32 is now emulated correctly.
>
> Validation:
> The patch is validated to have fixed the issue with test cases running
> on a modified version of QEMU that exposes misaligned faults [1], and
> a further modified version that removes tinst transformation [2]. The
> S-mode OS is a local build of Debian Trixie 6.12 kernel that enables
> COMPAT (RV32), and the U-mode test application exercises all integer
> and floating-point load/store (RVIFD64/32+RVC64/32) instructions with
> all possible imm values. The patch is also tested on real HW (Sifive
> P550/ESWIN EIC7700), which only supports RV64. On P550, the same test
> was validated both in U mode and VU mode, where the host runs a 6.12
> ESWIN vendor kernel that has some ESWIN SoC device driver patches [3]
> applied, and the guest runs the exact same Debian Trixie 6.12 kernel
> mentioned above.
>
> [1] https://github.com/ganboing/qemu/tree/ganboing-misalign
> [2] https://github.com/ganboing/qemu/tree/ganboing-misalign-no-tinst
> [3] https://github.com/sifiveinc/riscv-linux/tree/rel/kernel-6.12/hifive-premier-p550
>
> Fixes: 7219477f7b40 ("lib: Use MTINST CSR in misaligned load/store emulation")
> Fixes: b5ae8e8a650d ("lib: Add misaligned load/store trap handling")
> Fixes: 4c112650bbb0 ("lib: sbi: abstract out insn decoding to unify mem fault handlers")
> Signed-off-by: Bo Gan <ganboing at gmail.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup

> ---
>  lib/sbi/sbi_trap_ldst.c | 436 ++++++++++++++++++++++++++++------------
>  1 file changed, 308 insertions(+), 128 deletions(-)
>
> diff --git a/lib/sbi/sbi_trap_ldst.c b/lib/sbi/sbi_trap_ldst.c
> index ad19926a..c1392251 100644
> --- a/lib/sbi/sbi_trap_ldst.c
> +++ b/lib/sbi/sbi_trap_ldst.c
> @@ -44,28 +44,34 @@ ulong sbi_misaligned_tinst_fixup(ulong orig_tinst, ulong new_tinst,
>                 return orig_tinst | (addr_offset << SH_RS1);
>  }
>
> +static inline bool sbi_trap_tinst_valid(ulong tinst)
> +{
> +       /*
> +        * Bit[0] == 1 implies trapped instruction value is
> +        * transformed instruction or custom instruction.
> +        * Also do proper checking per Privileged ISA 19.6.3,
> +        * and make sure high 32 bits of tinst is 0
> +        */
> +       return tinst == (uint32_t)tinst && (tinst & 0x1);
> +}
> +
>  static int sbi_trap_emulate_load(struct sbi_trap_context *tcntx,
>                                  sbi_trap_ld_emulator emu)
>  {
>         const struct sbi_trap_info *orig_trap = &tcntx->trap;
>         struct sbi_trap_regs *regs = &tcntx->regs;
> -       ulong insn, insn_len;
> +       ulong insn, insn_len, imm = 0, shift = 0, off = 0;
>         union sbi_ldst_data val = { 0 };
>         struct sbi_trap_info uptrap;
> -       int rc, fp = 0, shift = 0, len = 0;
> +       bool xform = false, fp = false, c_load = false, c_ldsp = false;
> +       int rc, len = 0, prev_xlen = 0;
>
> -       if (orig_trap->tinst & 0x1) {
> -               /*
> -                * Bit[0] == 1 implies trapped instruction value is
> -                * transformed instruction or custom instruction.
> -                */
> +       if (sbi_trap_tinst_valid(orig_trap->tinst)) {
> +               xform    = true;
>                 insn     = orig_trap->tinst | INSN_16BIT_MASK;
>                 insn_len = (orig_trap->tinst & 0x2) ? INSN_LEN(insn) : 2;
>         } else {
> -               /*
> -                * Bit[0] == 0 implies trapped instruction value is
> -                * zero or special value.
> -                */
> +               /* trapped instruction value is zero or special value */
>                 insn = sbi_get_insn(regs->mepc, &uptrap);
>                 if (uptrap.cause) {
>                         return sbi_trap_redirect(regs, &uptrap);
> @@ -73,93 +79,176 @@ static int sbi_trap_emulate_load(struct sbi_trap_context *tcntx,
>                 insn_len = INSN_LEN(insn);
>         }
>
> +       /**
> +        * Common for RV32/RV64:
> +        *    lb, lbu, lh, lhu, lw, flw, flw
> +        *    c.lbu, c.lh, c.lhu, c.lw, c.lwsp, c.fld, c.fldsp
> +        */
>         if ((insn & INSN_MASK_LB) == INSN_MATCH_LB) {
> -               len   = 1;
> -               shift = 8 * (sizeof(ulong) - len);
> +               len = -1;
>         } else if ((insn & INSN_MASK_LBU) == INSN_MATCH_LBU) {
>                 len = 1;
> -       } else if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
> -               len   = 4;
> -               shift = 8 * (sizeof(ulong) - len);
> -#if __riscv_xlen == 64
> -       } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
> -               len   = 8;
> -               shift = 8 * (sizeof(ulong) - len);
> -       } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
> -               len = 4;
> -#endif
> -#ifdef __riscv_flen
> -       } else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
> -               fp  = 1;
> -               len = 8;
> -       } else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
> -               fp  = 1;
> -               len = 4;
> -#endif
> +       } else if ((insn & INSN_MASK_C_LBU) == INSN_MATCH_C_LBU) {
> +               /* Zcb */
> +               len = 1;
> +               imm = RVC_LB_IMM(insn);
> +               c_load = true;
>         } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) {
> -               len   = 2;
> -               shift = 8 * (sizeof(ulong) - len);
> +               len = -2;
> +       } else if ((insn & INSN_MASK_C_LH) == INSN_MATCH_C_LH) {
> +               /* Zcb */
> +               len = -2;
> +               imm = RVC_LH_IMM(insn);
> +               c_load = true;
>         } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) {
>                 len = 2;
> -#if __riscv_xlen >= 64
> -       } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
> -               len   = 8;
> -               shift = 8 * (sizeof(ulong) - len);
> -               insn  = RVC_RS2S(insn) << SH_RD;
> -       } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
> -                  ((insn >> SH_RD) & 0x1f)) {
> -               len   = 8;
> -               shift = 8 * (sizeof(ulong) - len);
> -#endif
> +       } else if ((insn & INSN_MASK_C_LHU) == INSN_MATCH_C_LHU) {
> +               /* Zcb */
> +               len = 2;
> +               imm = RVC_LH_IMM(insn);
> +               c_load = true;
> +       } else if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
> +               len = -4;
>         } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) {
> -               len   = 4;
> -               shift = 8 * (sizeof(ulong) - len);
> -               insn  = RVC_RS2S(insn) << SH_RD;
> +               /* Zca */
> +               len = -4;
> +               imm = RVC_LW_IMM(insn);
> +               c_load = true;
>         } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP &&
> -                  ((insn >> SH_RD) & 0x1f)) {
> -               len   = 4;
> -               shift = 8 * (sizeof(ulong) - len);
> +               GET_RD_NUM(insn)) {
> +               /* Zca */
> +               len = -4;
> +               imm = RVC_LWSP_IMM(insn);
> +               c_ldsp = true;
>  #ifdef __riscv_flen
> +       } else if ((insn & INSN_MASK_FLW) == INSN_MATCH_FLW) {
> +               len = 4;
> +               fp = true;
> +       } else if ((insn & INSN_MASK_FLD) == INSN_MATCH_FLD) {
> +               len = 8;
> +               fp = true;
>         } else if ((insn & INSN_MASK_C_FLD) == INSN_MATCH_C_FLD) {
> -               fp   = 1;
> -               len  = 8;
> -               insn = RVC_RS2S(insn) << SH_RD;
> +               /* Zcd */
> +               len = 8;
> +               imm = RVC_LD_IMM(insn);
> +               c_load = true;
> +               fp = true;
>         } else if ((insn & INSN_MASK_C_FLDSP) == INSN_MATCH_C_FLDSP) {
> -               fp  = 1;
> +               /* Zcd */
>                 len = 8;
> -#if __riscv_xlen == 32
> -       } else if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) {
> -               fp   = 1;
> -               len  = 4;
> -               insn = RVC_RS2S(insn) << SH_RD;
> -       } else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) {
> -               fp  = 1;
> -               len = 4;
> +               imm = RVC_LDSP_IMM(insn);
> +               c_ldsp = true;
> +               fp = true;
>  #endif
> +       } else {
> +               prev_xlen = sbi_regs_prev_xlen(regs);
> +       }
> +
> +       /**
> +        * Must distinguish between rv64 and rv32, RVC instructions have
> +        * overlapping encoding:
> +        *     c.ld in rv64 == c.flw in rv32
> +        *     c.ldsp in rv64 == c.flwsp in rv32
> +        */
> +       if (prev_xlen == 64) {
> +               /* RV64 Only: lwu, ld, c.ld, c.ldsp  */
> +               if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) {
> +                       len = 4;
> +               } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) {
> +                       len = 8;
> +               } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) {
> +                       /* Zca */
> +                       len = 8;
> +                       imm = RVC_LD_IMM(insn);
> +                       c_load = true;
> +               } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP &&
> +                       GET_RD_NUM(insn)) {
> +                       /* Zca */
> +                       len = 8;
> +                       imm = RVC_LDSP_IMM(insn);
> +                       c_ldsp = true;
> +               }
> +#ifdef __riscv_flen
> +       } else if (prev_xlen == 32) {
> +               /* RV32 Only: c.flw, c.flwsp */
> +               if ((insn & INSN_MASK_C_FLW) == INSN_MATCH_C_FLW) {
> +                       /* Zcf */
> +                       len = 4;
> +                       imm = RVC_LW_IMM(insn);
> +                       c_load = true;
> +                       fp = true;
> +               } else if ((insn & INSN_MASK_C_FLWSP) == INSN_MATCH_C_FLWSP) {
> +                       /* Zcf */
> +                       len = 4;
> +                       imm = RVC_LWSP_IMM(insn);
> +                       c_ldsp = true;
> +                       fp = true;
> +               }
>  #endif
> -       } else if ((insn & INSN_MASK_C_LHU) == INSN_MATCH_C_LHU) {
> -               len = 2;
> -               insn = RVC_RS2S(insn) << SH_RD;
> -       } else if ((insn & INSN_MASK_C_LH) == INSN_MATCH_C_LH) {
> -               len = 2;
> +       }
> +
> +       if (len < 0) {
> +               len = -len;
>                 shift = 8 * (sizeof(ulong) - len);
> -               insn = RVC_RS2S(insn) << SH_RD;
>         }
>
> -       rc = emu(insn, len, orig_trap->tval, &val, tcntx);
> +       if (!len) // Unknown instruction
> +               goto do_emu;
> +
> +#if !defined(OPENSBI_DEBUG)
> +       /**
> +        * For misaligned faults. Skip offset calculation unless DEBUG
> +        * builds. It helps validating OpenSBI and HW.
> +        */
> +       if (orig_trap->cause == CAUSE_MISALIGNED_LOAD)
> +               goto do_emu;
> +#endif
> +
> +       if (xform)
> +               /* Transformed insn */
> +               off = GET_RS1_NUM(insn);
> +       else if (c_load)
> +               /* non SP-based compressed load */
> +               off = orig_trap->tval - GET_RS1S(insn, regs) - imm;
> +       else if (c_ldsp)
> +               /* SP-based compressed load */
> +               off = orig_trap->tval - REG_VAL(2, regs) - imm;
> +       else
> +               /* I-type non-compressed load */
> +               off = orig_trap->tval - GET_RS1(insn, regs) - (ulong)IMM_I(insn);
> +       /**
> +        * Normalize offset, in case the XLEN of unpriv mode is smaller,
> +        * and/or pointer masking is in effect
> +        */
> +       off &= (len - 1);
> +
> +do_emu:
> +       rc = emu(insn, len, orig_trap->tval - off, &val, tcntx);
>         if (rc <= 0)
>                 return rc;
>         if (!len)
>                 goto epc_fixup;
>
> -       if (!fp)
> -               SET_RD(insn, regs, ((long)(val.data_ulong << shift)) >> shift);
> +       if (!fp) {
> +               ulong v = ((long)(val.data_ulong << shift)) >> shift;
> +
> +               if (c_load)
> +                       SET_RDS(insn, regs, v);
> +               else
> +                       SET_RD(insn, regs, v);
>  #ifdef __riscv_flen
> -       else if (len == 8)
> -               SET_F64_RD(insn, regs, val.data_u64);
> -       else
> -               SET_F32_RD(insn, regs, val.data_ulong);
> +       } else if (len == 8) {
> +               if (c_load)
> +                       SET_F64_RDS(insn, regs, val.data_u64);
> +               else
> +                       SET_F64_RD(insn, regs, val.data_u64);
> +       } else {
> +               if (c_load)
> +                       SET_F32_RDS(insn, regs, val.data_ulong);
> +               else
> +                       SET_F32_RD(insn, regs, val.data_ulong);
>  #endif
> +       }
>
>  epc_fixup:
>         regs->mepc += insn_len;
> @@ -172,23 +261,18 @@ static int sbi_trap_emulate_store(struct sbi_trap_context *tcntx,
>  {
>         const struct sbi_trap_info *orig_trap = &tcntx->trap;
>         struct sbi_trap_regs *regs = &tcntx->regs;
> -       ulong insn, insn_len;
> +       ulong insn, insn_len, imm = 0, off = 0;
>         union sbi_ldst_data val;
>         struct sbi_trap_info uptrap;
> -       int rc, len = 0;
> +       bool xform = false, fp = false, c_store = false, c_stsp = false;
> +       int rc, len = 0, prev_xlen = 0;
>
> -       if (orig_trap->tinst & 0x1) {
> -               /*
> -                * Bit[0] == 1 implies trapped instruction value is
> -                * transformed instruction or custom instruction.
> -                */
> +       if (sbi_trap_tinst_valid(orig_trap->tinst)) {
> +               xform    = true;
>                 insn     = orig_trap->tinst | INSN_16BIT_MASK;
>                 insn_len = (orig_trap->tinst & 0x2) ? INSN_LEN(insn) : 2;
>         } else {
> -               /*
> -                * Bit[0] == 0 implies trapped instruction value is
> -                * zero or special value.
> -                */
> +               /* trapped instruction value is zero or special value */
>                 insn = sbi_get_insn(regs->mepc, &uptrap);
>                 if (uptrap.cause) {
>                         return sbi_trap_redirect(regs, &uptrap);
> @@ -196,62 +280,158 @@ static int sbi_trap_emulate_store(struct sbi_trap_context *tcntx,
>                 insn_len = INSN_LEN(insn);
>         }
>
> -       val.data_ulong = GET_RS2(insn, regs);
> -
> +       /**
> +        * Common for RV32/RV64:
> +        *    sb, sh, sw, fsw, fsd
> +        *    c.sb, c.sh, c.sw, c.swsp, c.fsd, c.fsdsp
> +        */
>         if ((insn & INSN_MASK_SB) == INSN_MATCH_SB) {
>                 len = 1;
> -       } else if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
> -               len = 4;
> -#if __riscv_xlen == 64
> -       } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
> -               len = 8;
> -#endif
> -#ifdef __riscv_flen
> -       } else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
> -               len          = 8;
> -               val.data_u64 = GET_F64_RS2(insn, regs);
> -       } else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
> -               len            = 4;
> -               val.data_ulong = GET_F32_RS2(insn, regs);
> -#endif
> +       } else if ((insn & INSN_MASK_C_SB) == INSN_MATCH_C_SB) {
> +               /* Zcb */
> +               len = 1;
> +               imm = RVC_SB_IMM(insn);
> +               c_store = true;
>         } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) {
>                 len = 2;
> -#if __riscv_xlen >= 64
> -       } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
> -               len            = 8;
> -               val.data_ulong = GET_RS2S(insn, regs);
> -       } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP) {
> -               len            = 8;
> -               val.data_ulong = GET_RS2C(insn, regs);
> -#endif
> +       } else if ((insn & INSN_MASK_C_SH) == INSN_MATCH_C_SH) {
> +               /* Zcb */
> +               len = 2;
> +               imm = RVC_SH_IMM(insn);
> +               c_store = true;
> +       } else if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
> +               len = 4;
>         } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) {
> -               len            = 4;
> -               val.data_ulong = GET_RS2S(insn, regs);
> +               /* Zca */
> +               len = 4;
> +               imm = RVC_SW_IMM(insn);
> +               c_store = true;
>         } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP) {
> -               len            = 4;
> -               val.data_ulong = GET_RS2C(insn, regs);
> +               /* Zca */
> +               len = 4;
> +               imm = RVC_SWSP_IMM(insn);
> +               c_stsp = true;
>  #ifdef __riscv_flen
> +       } else if ((insn & INSN_MASK_FSW) == INSN_MATCH_FSW) {
> +               len = 4;
> +               fp = true;
> +       } else if ((insn & INSN_MASK_FSD) == INSN_MATCH_FSD) {
> +               len = 8;
> +               fp = true;
>         } else if ((insn & INSN_MASK_C_FSD) == INSN_MATCH_C_FSD) {
> -               len          = 8;
> -               val.data_u64 = GET_F64_RS2S(insn, regs);
> +               /* Zcd */
> +               len = 8;
> +               imm = RVC_SD_IMM(insn);
> +               c_store = true;
> +               fp = true;
>         } else if ((insn & INSN_MASK_C_FSDSP) == INSN_MATCH_C_FSDSP) {
> -               len          = 8;
> -               val.data_u64 = GET_F64_RS2C(insn, regs);
> -#if __riscv_xlen == 32
> -       } else if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) {
> -               len            = 4;
> -               val.data_ulong = GET_F32_RS2S(insn, regs);
> -       } else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) {
> -               len            = 4;
> -               val.data_ulong = GET_F32_RS2C(insn, regs);
> +               /* Zcd */
> +               len = 8;
> +               imm = RVC_SDSP_IMM(insn);
> +               c_stsp = true;
> +               fp = true;
>  #endif
> +       } else {
> +               prev_xlen = sbi_regs_prev_xlen(regs);
> +       }
> +
> +       /**
> +        * Must distinguish between rv64 and rv32, RVC instructions have
> +        * overlapping encoding:
> +        *     c.sd in rv64 == c.fsw in rv32
> +        *     c.sdsp in rv64 == c.fswsp in rv32
> +        */
> +       if (prev_xlen == 64) {
> +               /* RV64 Only: sd, c.sd, c.sdsp */
> +               if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) {
> +                       len = 8;
> +               } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) {
> +                       /* Zca */
> +                       len = 8;
> +                       imm = RVC_SD_IMM(insn);
> +                       c_store = true;
> +               } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP) {
> +                       /* Zca */
> +                       len = 8;
> +                       imm = RVC_SDSP_IMM(insn);
> +                       c_stsp = true;
> +               }
> +#ifdef __riscv_flen
> +       } else if (prev_xlen == 32) {
> +               /* RV32 Only: c.fsw, c.fswsp */
> +               if ((insn & INSN_MASK_C_FSW) == INSN_MATCH_C_FSW) {
> +                       /* Zcf */
> +                       len = 4;
> +                       imm = RVC_SW_IMM(insn);
> +                       c_store = true;
> +                       fp = true;
> +               } else if ((insn & INSN_MASK_C_FSWSP) == INSN_MATCH_C_FSWSP) {
> +                       /* Zcf */
> +                       len = 4;
> +                       imm = RVC_SWSP_IMM(insn);
> +                       c_stsp = true;
> +                       fp = true;
> +               }
> +#endif
> +       }
> +
> +       if (!fp) {
> +               if (c_store)
> +                       val.data_ulong = GET_RS2S(insn, regs);
> +               else if (c_stsp)
> +                       val.data_ulong = GET_RS2C(insn, regs);
> +               else
> +                       val.data_ulong = GET_RS2(insn, regs);
> +#ifdef __riscv_flen
> +       } else if (len == 8) {
> +               if (c_store)
> +                       val.data_u64 = GET_F64_RS2S(insn, regs);
> +               else if (c_stsp)
> +                       val.data_u64 = GET_F64_RS2C(insn, regs);
> +               else
> +                       val.data_u64 = GET_F64_RS2(insn, regs);
> +       } else {
> +               if (c_store)
> +                       val.data_ulong = GET_F32_RS2S(insn, regs);
> +               else if (c_stsp)
> +                       val.data_ulong = GET_F32_RS2C(insn, regs);
> +               else
> +                       val.data_ulong = GET_F32_RS2(insn, regs);
>  #endif
> -       } else if ((insn & INSN_MASK_C_SH) == INSN_MATCH_C_SH) {
> -               len             = 2;
> -               val.data_ulong = GET_RS2S(insn, regs);
>         }
>
> -       rc = emu(insn, len, orig_trap->tval, val, tcntx);
> +       if (!len) // Unknown instruction
> +               goto do_emu;
> +
> +#if !defined(OPENSBI_DEBUG)
> +       /**
> +        * For misaligned faults. Skip offset calculation unless DEBUG
> +        * builds. It helps validating OpenSBI and HW.
> +        */
> +       if (orig_trap->cause == CAUSE_MISALIGNED_STORE)
> +               goto do_emu;
> +#endif
> +
> +       if (xform)
> +               /* Transformed insn */
> +               off = GET_RS1_NUM(insn);
> +       else if (c_store)
> +               /* non SP-based compressed store */
> +               off = orig_trap->tval - GET_RS1S(insn, regs) - imm;
> +       else if (c_stsp)
> +               /* SP-based compressed store */
> +               off = orig_trap->tval - REG_VAL(2, regs) - imm;
> +       else
> +               /* S-type non-compressed store */
> +               off = orig_trap->tval - GET_RS1(insn, regs) - (ulong)IMM_S(insn);
> +       /**
> +        * Normalize offset, in case the XLEN of unpriv mode is smaller,
> +        * and/or pointer masking is in effect
> +        */
> +       off &= (len - 1);
> +
> +do_emu:
> +       rc = emu(insn, len, orig_trap->tval - off, val, tcntx);
>         if (rc <= 0)
>                 return rc;
>
> --
> 2.34.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi



More information about the opensbi mailing list