target/riscv: Introduce elp state and enabling controls for zicfilp

zicfilp introduces a new state elp ("expected landing pad") in cpu.
During normal execution, elp is idle (NO_LP_EXPECTED) i.e not expecting
landing pad. On an indirect call, elp moves LP_EXPECTED. When elp is
LP_EXPECTED, only a subsquent landing pad instruction can set state back
to NO_LP_EXPECTED. On reset, elp is set to NO_LP_EXPECTED.

zicfilp is enabled via bit2 in *envcfg CSRs. Enabling control for M-mode
is in mseccfg CSR at bit position 10.

On trap, elp state is saved away in *status.
Adds elp to the migration state as well.

Signed-off-by: Deepak Gupta <debug@rivosinc.com>
Co-developed-by: Jim Shu <jim.shu@sifive.com>
Co-developed-by: Andy Chiu <andy.chiu@sifive.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20241008225010.1861630-4-debug@rivosinc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Deepak Gupta 2024-10-08 15:49:53 -07:00 committed by Alistair Francis
parent bd08b22e56
commit 4923f672e3
7 changed files with 68 additions and 1 deletions

View File

@ -1011,6 +1011,9 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
env->menvcfg = 0;
#endif
/* on reset elp is clear */
env->elp = false;
env->xl = riscv_cpu_mxl(env);
riscv_cpu_update_mask(env);
cs->exception_index = RISCV_EXCP_NONE;

View File

@ -230,6 +230,8 @@ struct CPUArchState {
target_ulong jvt;
/* elp state for zicfilp extension */
bool elp;
#ifdef CONFIG_USER_ONLY
uint32_t elf_flags;
#endif

View File

@ -552,6 +552,8 @@
#define MSTATUS_TVM 0x00100000 /* since: priv-1.10 */
#define MSTATUS_TW 0x00200000 /* since: priv-1.10 */
#define MSTATUS_TSR 0x00400000 /* since: priv-1.10 */
#define MSTATUS_SPELP 0x00800000 /* zicfilp */
#define MSTATUS_MPELP 0x020000000000 /* zicfilp */
#define MSTATUS_GVA 0x4000000000ULL
#define MSTATUS_MPV 0x8000000000ULL
@ -582,6 +584,7 @@ typedef enum {
#define SSTATUS_XS 0x00018000
#define SSTATUS_SUM 0x00040000 /* since: priv-1.10 */
#define SSTATUS_MXR 0x00080000
#define SSTATUS_SPELP MSTATUS_SPELP /* zicfilp */
#define SSTATUS64_UXL 0x0000000300000000ULL
@ -754,6 +757,7 @@ typedef enum RISCVException {
/* Execution environment configuration bits */
#define MENVCFG_FIOM BIT(0)
#define MENVCFG_LPE BIT(2) /* zicfilp */
#define MENVCFG_CBIE (3UL << 4)
#define MENVCFG_CBCFE BIT(6)
#define MENVCFG_CBZE BIT(7)
@ -767,11 +771,13 @@ typedef enum RISCVException {
#define MENVCFGH_STCE BIT(31)
#define SENVCFG_FIOM MENVCFG_FIOM
#define SENVCFG_LPE MENVCFG_LPE
#define SENVCFG_CBIE MENVCFG_CBIE
#define SENVCFG_CBCFE MENVCFG_CBCFE
#define SENVCFG_CBZE MENVCFG_CBZE
#define HENVCFG_FIOM MENVCFG_FIOM
#define HENVCFG_LPE MENVCFG_LPE
#define HENVCFG_CBIE MENVCFG_CBIE
#define HENVCFG_CBCFE MENVCFG_CBCFE
#define HENVCFG_CBZE MENVCFG_CBZE

View File

@ -1598,6 +1598,11 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
}
}
/* If cfi lp extension is available, then apply cfi lp mask */
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= (MSTATUS_MPELP | MSTATUS_SPELP);
}
mstatus = (mstatus & ~mask) | (val & mask);
env->mstatus = mstatus;
@ -2344,6 +2349,10 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
(cfg->ext_sstc ? MENVCFG_STCE : 0) |
(cfg->ext_svadu ? MENVCFG_ADUE : 0);
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= MENVCFG_LPE;
}
}
env->menvcfg = (env->menvcfg & ~mask) | (val & mask);
@ -2396,6 +2405,10 @@ static RISCVException write_senvcfg(CPURISCVState *env, int csrno,
return ret;
}
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= SENVCFG_LPE;
}
env->senvcfg = (env->senvcfg & ~mask) | (val & mask);
return RISCV_EXCP_NONE;
}
@ -2433,6 +2446,10 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
if (riscv_cpu_mxl(env) == MXL_RV64) {
mask |= env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE);
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= HENVCFG_LPE;
}
}
env->henvcfg = (env->henvcfg & ~mask) | (val & mask);
@ -2897,6 +2914,10 @@ static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno,
mask |= SSTATUS64_UXL;
}
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= SSTATUS_SPELP;
}
*val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus));
return RISCV_EXCP_NONE;
}
@ -2908,6 +2929,11 @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno,
if (env->xl != MXL_RV32 || env->debugger) {
mask |= SSTATUS64_UXL;
}
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= SSTATUS_SPELP;
}
/* TODO: Use SXL not MXL. */
*val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask);
return RISCV_EXCP_NONE;
@ -2923,6 +2949,11 @@ static RISCVException write_sstatus(CPURISCVState *env, int csrno,
mask |= SSTATUS64_UXL;
}
}
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= SSTATUS_SPELP;
}
target_ulong newval = (env->mstatus & ~mask) | (val & mask);
return write_mstatus(env, CSR_MSTATUS, newval);
}

View File

@ -350,6 +350,24 @@ static const VMStateDescription vmstate_jvt = {
}
};
static bool elp_needed(void *opaque)
{
RISCVCPU *cpu = opaque;
return cpu->cfg.ext_zicfilp;
}
static const VMStateDescription vmstate_elp = {
.name = "cpu/elp",
.version_id = 1,
.minimum_version_id = 1,
.needed = elp_needed,
.fields = (const VMStateField[]) {
VMSTATE_BOOL(env.elp, RISCVCPU),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_riscv_cpu = {
.name = "cpu",
.version_id = 10,
@ -422,6 +440,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_debug,
&vmstate_smstateen,
&vmstate_jvt,
&vmstate_elp,
NULL
}
};

View File

@ -598,6 +598,11 @@ void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
val &= ~(MSECCFG_MMWP | MSECCFG_MML | MSECCFG_RLB);
}
/* M-mode forward cfi to be enabled if cfi extension is implemented */
if (env_archcpu(env)->cfg.ext_zicfilp) {
val |= (val & MSECCFG_MLPE);
}
env->mseccfg = val;
}

View File

@ -44,7 +44,8 @@ typedef enum {
MSECCFG_MMWP = 1 << 1,
MSECCFG_RLB = 1 << 2,
MSECCFG_USEED = 1 << 8,
MSECCFG_SSEED = 1 << 9
MSECCFG_SSEED = 1 << 9,
MSECCFG_MLPE = 1 << 10,
} mseccfg_field_t;
typedef struct {