Message ID | 20240826152949.294506-3-debug@rivosinc.com |
---|---|
State | New |
Headers | show |
Series | riscv support for control flow integrity extensions | expand |
On Tue, Aug 27, 2024 at 1:30 AM Deepak Gupta <debug@rivosinc.com> wrote: > > 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> Alistair > --- > target/riscv/cpu.c | 3 +++ > target/riscv/cpu.h | 2 ++ > target/riscv/cpu_bits.h | 6 ++++++ > target/riscv/csr.c | 31 +++++++++++++++++++++++++++++++ > target/riscv/machine.c | 19 +++++++++++++++++++ > target/riscv/pmp.c | 5 +++++ > target/riscv/pmp.h | 3 ++- > 7 files changed, 68 insertions(+), 1 deletion(-) > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > index 5dfb3f39ab..8e1f05e5b1 100644 > --- a/target/riscv/cpu.c > +++ b/target/riscv/cpu.c > @@ -994,6 +994,9 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) > /* mmte is supposed to have pm.current hardwired to 1 */ > env->mmte |= (EXT_STATUS_INITIAL | MMTE_M_PM_CURRENT); > > + /* on reset elp is clear */ > + env->elp = false; > + > /* > * Bits 10, 6, 2 and 12 of mideleg are read only 1 when the Hypervisor > * extension is enabled. > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index 87742047ce..f966c36a31 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -222,6 +222,8 @@ struct CPUArchState { > > target_ulong jvt; > > + /* elp state for zicfilp extension */ > + bool elp; > #ifdef CONFIG_USER_ONLY > uint32_t elf_flags; > #endif > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h > index c257c5ed7d..b05ebe6f29 100644 > --- a/target/riscv/cpu_bits.h > +++ b/target/riscv/cpu_bits.h > @@ -545,6 +545,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 > > @@ -575,6 +577,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 > > @@ -747,6 +750,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) > @@ -760,11 +764,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 > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index 432c59dc66..5771a14848 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -1400,6 +1400,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; > @@ -2101,6 +2106,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); > > @@ -2153,6 +2162,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; > } > @@ -2190,6 +2203,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); > @@ -2654,6 +2671,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; > } > @@ -2665,6 +2686,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; > @@ -2680,6 +2706,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); > } > diff --git a/target/riscv/machine.c b/target/riscv/machine.c > index 76f2150f78..873957c4ab 100644 > --- a/target/riscv/machine.c > +++ b/target/riscv/machine.c > @@ -351,6 +351,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, > @@ -423,6 +441,7 @@ const VMStateDescription vmstate_riscv_cpu = { > &vmstate_debug, > &vmstate_smstateen, > &vmstate_jvt, > + &vmstate_elp, > NULL > } > }; > diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c > index 9eea397e72..1111d08d08 100644 > --- a/target/riscv/pmp.c > +++ b/target/riscv/pmp.c > @@ -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; > } > > diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h > index f5c10ce85c..e0530a17a3 100644 > --- a/target/riscv/pmp.h > +++ b/target/riscv/pmp.h > @@ -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 { > -- > 2.44.0 > >
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 5dfb3f39ab..8e1f05e5b1 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -994,6 +994,9 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) /* mmte is supposed to have pm.current hardwired to 1 */ env->mmte |= (EXT_STATUS_INITIAL | MMTE_M_PM_CURRENT); + /* on reset elp is clear */ + env->elp = false; + /* * Bits 10, 6, 2 and 12 of mideleg are read only 1 when the Hypervisor * extension is enabled. diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 87742047ce..f966c36a31 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -222,6 +222,8 @@ struct CPUArchState { target_ulong jvt; + /* elp state for zicfilp extension */ + bool elp; #ifdef CONFIG_USER_ONLY uint32_t elf_flags; #endif diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index c257c5ed7d..b05ebe6f29 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -545,6 +545,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 @@ -575,6 +577,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 @@ -747,6 +750,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) @@ -760,11 +764,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 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 432c59dc66..5771a14848 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1400,6 +1400,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; @@ -2101,6 +2106,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); @@ -2153,6 +2162,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; } @@ -2190,6 +2203,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); @@ -2654,6 +2671,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; } @@ -2665,6 +2686,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; @@ -2680,6 +2706,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); } diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 76f2150f78..873957c4ab 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -351,6 +351,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, @@ -423,6 +441,7 @@ const VMStateDescription vmstate_riscv_cpu = { &vmstate_debug, &vmstate_smstateen, &vmstate_jvt, + &vmstate_elp, NULL } }; diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 9eea397e72..1111d08d08 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -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; } diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h index f5c10ce85c..e0530a17a3 100644 --- a/target/riscv/pmp.h +++ b/target/riscv/pmp.h @@ -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 {