From: Frédéric Pétrot <[email protected]> UndefinedBehaviorSanitizer reports an undefined behavior when setting the Interrupt flag (msb) in the [ms]cause registers due to an out of bounds shift.
To prevent this, we introduce fields to hold the interrupt flag in all "versions" of the cause register and build the expected values on the fly by oring it with the proper cause. Handling of vscause assumes it has the same xlen than cause. Reported-by: Peter Maydell <[email protected]> Signed-off-by: Frédéric Pétrot <[email protected]> --- target/riscv/cpu.c | 1 + target/riscv/cpu.h | 4 ++ target/riscv/tcg/cpu_helper.c | 20 +++++++-- target/riscv/tcg/csr.c | 79 +++++++++++++++++++++++++++++++---- 4 files changed, 93 insertions(+), 11 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 362e561809..d473c94e21 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1021,6 +1021,7 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) env->mstatus = set_field(env->mstatus, MSTATUS_SBE, cpu->cfg.big_endian); env->mstatus = set_field(env->mstatus, MSTATUS_UBE, cpu->cfg.big_endian); env->mcause = 0; + env->mcause_int = 0; env->miclaim = MIP_SGEIP; env->pc = env->resetvec; env->bins = 0; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 49a1186bdb..e7fe1102c3 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -354,10 +354,12 @@ struct CPUArchState { uint64_t stvec; uint64_t sepc; uint64_t scause; + uint64_t scause_int; uint64_t mtvec; uint64_t mepc; uint64_t mcause; + uint64_t mcause_int; uint64_t mtval; /* since: priv-1.10.0 */ uint64_t mctrctl; @@ -417,6 +419,7 @@ struct CPUArchState { uint64_t vsscratch; uint64_t vsepc; uint64_t vscause; + uint64_t vscause_int; uint64_t vstval; uint64_t vsatp; @@ -431,6 +434,7 @@ struct CPUArchState { uint64_t sscratch_hs; uint64_t sepc_hs; uint64_t scause_hs; + uint64_t scause_int_hs; uint64_t stval_hs; uint64_t satp_hs; uint64_t mstatus_hs; diff --git a/target/riscv/tcg/cpu_helper.c b/target/riscv/tcg/cpu_helper.c index 58e98e975c..a3ba7e9c42 100644 --- a/target/riscv/tcg/cpu_helper.c +++ b/target/riscv/tcg/cpu_helper.c @@ -585,7 +585,9 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) env->sepc = env->sepc_hs; env->vscause = env->scause; + env->vscause_int = env->scause_int; env->scause = env->scause_hs; + env->scause_int = env->scause_int_hs; env->vstval = env->stval; env->stval = env->stval_hs; @@ -608,7 +610,9 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) env->sepc = env->vsepc; env->scause_hs = env->scause; + env->scause_int_hs = env->scause_int; env->scause = env->vscause; + env->scause_int = env->vscause_int; env->stval_hs = env->stval; env->stval = env->vstval; @@ -2375,7 +2379,12 @@ void riscv_cpu_do_interrupt(CPUState *cs) } env->mstatus = s; sxlen = 16 << riscv_cpu_sxl(env); - env->scause = cause | ((target_ulong)async << (sxlen - 1)); + env->scause = cause; + if (riscv_cpu_sxl(env) != MXL_RV128) { + env->scause_int = (target_ulong)async << (sxlen - 1); + } else { + env->scause_int = (target_ulong)async << 63; + } env->sepc = env->pc; env->stval = tval; env->htval = htval; @@ -2447,9 +2456,14 @@ void riscv_cpu_do_interrupt(CPUState *cs) s = set_field(s, MSTATUS_MDT, 1); } env->mstatus = s; - env->mcause = cause | ((target_ulong)async << (mxlen - 1)); + env->mcause = cause; + if (riscv_cpu_mxl(env) != MXL_RV128) { + env->mcause_int = (target_ulong)async << (mxlen - 1); + } else { + env->mcause_int = (target_ulong)async << 63; + } if (smode_double_trap) { - env->mtval2 = env->mcause; + env->mtval2 = env->mcause_int | env->mcause; env->mcause = RISCV_EXCP_DOUBLE_TRAP; } else { env->mtval2 = mtval2; diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c index c3ef16cf1a..9549f5e6c5 100644 --- a/target/riscv/tcg/csr.c +++ b/target/riscv/tcg/csr.c @@ -3234,14 +3234,37 @@ static RISCVException write_mepc(CPURISCVState *env, int csrno, static RISCVException read_mcause(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->mcause; + *val = env->mcause_int | env->mcause; return RISCV_EXCP_NONE; } +static uint64_t cause_int_mask(RISCVMXL xl) +{ + g_assert(xl != MXL_RV128); + return 1ULL << ((16 << xl) - 1); +} + static RISCVException write_mcause(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - env->mcause = val; + env->mcause = val & (cause_int_mask(riscv_cpu_xlen(env)) - 1); + env->mcause_int = val & cause_int_mask(riscv_cpu_xlen(env)); + return RISCV_EXCP_NONE; +} + +static RISCVException read_mcause_i128(CPURISCVState *env, int csrno, + Int128 *val) +{ + *val = int128_make128(env->mcause, env->mcause_int); + + return RISCV_EXCP_NONE; +} + +static RISCVException write_mcause_i128(CPURISCVState *env, int csrno, + Int128 val) +{ + env->mcause = int128_getlo(val); + env->mcause_int = int128_gethi(val); return RISCV_EXCP_NONE; } @@ -4494,14 +4517,31 @@ static RISCVException write_sepc(CPURISCVState *env, int csrno, static RISCVException read_scause(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->scause; + *val = env->scause_int | env->scause; return RISCV_EXCP_NONE; } static RISCVException write_scause(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - env->scause = val; + env->scause = val & (cause_int_mask(riscv_cpu_sxl(env)) - 1); + env->scause_int = val & cause_int_mask(riscv_cpu_sxl(env)); + return RISCV_EXCP_NONE; +} + +static RISCVException read_scause_i128(CPURISCVState *env, int csrno, + Int128 *val) +{ + *val = int128_make128(env->scause, env->scause_int); + + return RISCV_EXCP_NONE; +} + +static RISCVException write_scause_i128(CPURISCVState *env, int csrno, + Int128 val) +{ + env->scause = int128_getlo(val); + env->scause_int = int128_gethi(val); return RISCV_EXCP_NONE; } @@ -5532,14 +5572,16 @@ static RISCVException write_vsepc(CPURISCVState *env, int csrno, static RISCVException read_vscause(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->vscause; + *val = env->vscause_int | env->vscause; return RISCV_EXCP_NONE; } static RISCVException write_vscause(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { - env->vscause = val; + /* Assumes vxlen == sxlen */ + env->vscause = val & (cause_int_mask(riscv_cpu_sxl(env)) - 1); + env->vscause_int = val & cause_int_mask(riscv_cpu_sxl(env)); return RISCV_EXCP_NONE; } @@ -5632,6 +5674,24 @@ static RISCVException write_pmpcfg(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException read_pmpcfg_i128(CPURISCVState *env, int csrno, + Int128 *val) +{ + uint32_t reg_index = csrno - CSR_PMPCFG0; + + *val = pmpcfg_csr_read_i128(env, reg_index); + return RISCV_EXCP_NONE; +} + +static RISCVException write_pmpcfg_i128(CPURISCVState *env, int csrno, + Int128 val) +{ + uint32_t reg_index = csrno - CSR_PMPCFG0; + + pmpcfg_csr_write_i128(env, reg_index, val); + return RISCV_EXCP_NONE; +} + static RISCVException read_pmpaddr(CPURISCVState *env, int csrno, target_ulong *val) { @@ -6227,7 +6287,8 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MSCRATCH] = { "mscratch", any, read_mscratch, write_mscratch, NULL, read_mscratch_i128, write_mscratch_i128 }, [CSR_MEPC] = { "mepc", any, read_mepc, write_mepc }, - [CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause }, + [CSR_MCAUSE] = { "mcause", any, read_mcause, write_mcause, + NULL, read_mcause_i128, write_mcause_i128 }, [CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval }, [CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip }, @@ -6362,7 +6423,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_SSCRATCH] = { "sscratch", smode, read_sscratch, write_sscratch, NULL, read_sscratch_i128, write_sscratch_i128 }, [CSR_SEPC] = { "sepc", smode, read_sepc, write_sepc }, - [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause }, + [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause, + NULL, read_scause_i128, write_scause_i128 }, + [CSR_STVAL] = { "stval", smode, read_stval, write_stval }, [CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip }, [CSR_STIMECMP] = { "stimecmp", sstc, read_stimecmp, write_stimecmp, -- 2.43.0
