target/riscv: introduce ssp and enabling controls for zicfiss

zicfiss introduces a new state ssp ("shadow stack register") in cpu.
ssp is expressed as a new unprivileged csr (CSR_SSP=0x11) and holds
virtual address for shadow stack as programmed by software.

Shadow stack (for each mode) is enabled via bit3 in *envcfg CSRs.
Shadow stack can be enabled for a mode only if it's higher privileged
mode had it enabled for itself. M mode doesn't need enabling control,
it's always available if extension is available on cpu.

This patch also implements helper bcfi function which determines if bcfi
is enabled at current privilege or not.

Adds ssp to 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-12-debug@rivosinc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Deepak Gupta 2024-10-08 15:50:01 -07:00 committed by Alistair Francis
parent cf064a671a
commit 8205bc127a
6 changed files with 111 additions and 0 deletions

View File

@ -1014,6 +1014,8 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
/* on reset elp is clear */ /* on reset elp is clear */
env->elp = false; env->elp = false;
/* on reset ssp is set to 0 */
env->ssp = 0;
env->xl = riscv_cpu_mxl(env); env->xl = riscv_cpu_mxl(env);
riscv_cpu_update_mask(env); riscv_cpu_update_mask(env);

View File

@ -232,6 +232,8 @@ struct CPUArchState {
/* elp state for zicfilp extension */ /* elp state for zicfilp extension */
bool elp; bool elp;
/* shadow stack register for zicfiss extension */
target_ulong ssp;
/* sw check code for sw check exception */ /* sw check code for sw check exception */
target_ulong sw_check_code; target_ulong sw_check_code;
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
@ -550,6 +552,7 @@ bool riscv_cpu_vector_enabled(CPURISCVState *env);
void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable); void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch); int riscv_env_mmu_index(CPURISCVState *env, bool ifetch);
bool cpu_get_fcfien(CPURISCVState *env); bool cpu_get_fcfien(CPURISCVState *env);
bool cpu_get_bcfien(CPURISCVState *env);
G_NORETURN void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr, G_NORETURN void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type, MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr); int mmu_idx, uintptr_t retaddr);

View File

@ -34,6 +34,9 @@
/* Control and Status Registers */ /* Control and Status Registers */
/* zicfiss user ssp csr */
#define CSR_SSP 0x011
/* User Trap Setup */ /* User Trap Setup */
#define CSR_USTATUS 0x000 #define CSR_USTATUS 0x000
#define CSR_UIE 0x004 #define CSR_UIE 0x004
@ -761,6 +764,7 @@ typedef enum RISCVException {
/* Execution environment configuration bits */ /* Execution environment configuration bits */
#define MENVCFG_FIOM BIT(0) #define MENVCFG_FIOM BIT(0)
#define MENVCFG_LPE BIT(2) /* zicfilp */ #define MENVCFG_LPE BIT(2) /* zicfilp */
#define MENVCFG_SSE BIT(3) /* zicfiss */
#define MENVCFG_CBIE (3UL << 4) #define MENVCFG_CBIE (3UL << 4)
#define MENVCFG_CBCFE BIT(6) #define MENVCFG_CBCFE BIT(6)
#define MENVCFG_CBZE BIT(7) #define MENVCFG_CBZE BIT(7)
@ -775,12 +779,14 @@ typedef enum RISCVException {
#define SENVCFG_FIOM MENVCFG_FIOM #define SENVCFG_FIOM MENVCFG_FIOM
#define SENVCFG_LPE MENVCFG_LPE #define SENVCFG_LPE MENVCFG_LPE
#define SENVCFG_SSE MENVCFG_SSE
#define SENVCFG_CBIE MENVCFG_CBIE #define SENVCFG_CBIE MENVCFG_CBIE
#define SENVCFG_CBCFE MENVCFG_CBCFE #define SENVCFG_CBCFE MENVCFG_CBCFE
#define SENVCFG_CBZE MENVCFG_CBZE #define SENVCFG_CBZE MENVCFG_CBZE
#define HENVCFG_FIOM MENVCFG_FIOM #define HENVCFG_FIOM MENVCFG_FIOM
#define HENVCFG_LPE MENVCFG_LPE #define HENVCFG_LPE MENVCFG_LPE
#define HENVCFG_SSE MENVCFG_SSE
#define HENVCFG_CBIE MENVCFG_CBIE #define HENVCFG_CBIE MENVCFG_CBIE
#define HENVCFG_CBCFE MENVCFG_CBCFE #define HENVCFG_CBCFE MENVCFG_CBCFE
#define HENVCFG_CBZE MENVCFG_CBZE #define HENVCFG_CBZE MENVCFG_CBZE

View File

@ -91,6 +91,35 @@ bool cpu_get_fcfien(CPURISCVState *env)
} }
} }
bool cpu_get_bcfien(CPURISCVState *env)
{
/* no cfi extension, return false */
if (!env_archcpu(env)->cfg.ext_zicfiss) {
return false;
}
switch (env->priv) {
case PRV_U:
/*
* If S is not implemented then shadow stack for U can't be turned on
* It is checked in `riscv_cpu_validate_set_extensions`, so no need to
* check here or assert here
*/
return env->senvcfg & SENVCFG_SSE;
#ifndef CONFIG_USER_ONLY
case PRV_S:
if (env->virt_enabled) {
return env->henvcfg & HENVCFG_SSE;
}
return env->menvcfg & MENVCFG_SSE;
case PRV_M: /* M-mode shadow stack is always off */
return false;
#endif
default:
g_assert_not_reached();
}
}
void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
uint64_t *cs_base, uint32_t *pflags) uint64_t *cs_base, uint32_t *pflags)
{ {

View File

@ -184,6 +184,25 @@ static RISCVException zcmt(CPURISCVState *env, int csrno)
return RISCV_EXCP_NONE; return RISCV_EXCP_NONE;
} }
static RISCVException cfi_ss(CPURISCVState *env, int csrno)
{
if (!env_archcpu(env)->cfg.ext_zicfiss) {
return RISCV_EXCP_ILLEGAL_INST;
}
/* if bcfi not active for current env, access to csr is illegal */
if (!cpu_get_bcfien(env)) {
#if !defined(CONFIG_USER_ONLY)
if (env->debugger) {
return RISCV_EXCP_NONE;
}
#endif
return RISCV_EXCP_ILLEGAL_INST;
}
return RISCV_EXCP_NONE;
}
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
static RISCVException mctr(CPURISCVState *env, int csrno) static RISCVException mctr(CPURISCVState *env, int csrno)
{ {
@ -622,6 +641,19 @@ static RISCVException seed(CPURISCVState *env, int csrno)
#endif #endif
} }
/* zicfiss CSR_SSP read and write */
static int read_ssp(CPURISCVState *env, int csrno, target_ulong *val)
{
*val = env->ssp;
return RISCV_EXCP_NONE;
}
static int write_ssp(CPURISCVState *env, int csrno, target_ulong val)
{
env->ssp = val;
return RISCV_EXCP_NONE;
}
/* User Floating-Point CSRs */ /* User Floating-Point CSRs */
static RISCVException read_fflags(CPURISCVState *env, int csrno, static RISCVException read_fflags(CPURISCVState *env, int csrno,
target_ulong *val) target_ulong *val)
@ -2354,6 +2386,10 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
if (env_archcpu(env)->cfg.ext_zicfilp) { if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= MENVCFG_LPE; mask |= MENVCFG_LPE;
} }
if (env_archcpu(env)->cfg.ext_zicfiss) {
mask |= MENVCFG_SSE;
}
} }
env->menvcfg = (env->menvcfg & ~mask) | (val & mask); env->menvcfg = (env->menvcfg & ~mask) | (val & mask);
@ -2410,6 +2446,13 @@ static RISCVException write_senvcfg(CPURISCVState *env, int csrno,
mask |= SENVCFG_LPE; mask |= SENVCFG_LPE;
} }
/* Higher mode SSE must be ON for next-less mode SSE to be ON */
if (env_archcpu(env)->cfg.ext_zicfiss &&
get_field(env->menvcfg, MENVCFG_SSE) &&
(env->virt_enabled ? get_field(env->henvcfg, HENVCFG_SSE) : true)) {
mask |= SENVCFG_SSE;
}
env->senvcfg = (env->senvcfg & ~mask) | (val & mask); env->senvcfg = (env->senvcfg & ~mask) | (val & mask);
return RISCV_EXCP_NONE; return RISCV_EXCP_NONE;
} }
@ -2451,6 +2494,12 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
if (env_archcpu(env)->cfg.ext_zicfilp) { if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= HENVCFG_LPE; mask |= HENVCFG_LPE;
} }
/* H can light up SSE for VS only if HS had it from menvcfg */
if (env_archcpu(env)->cfg.ext_zicfiss &&
get_field(env->menvcfg, MENVCFG_SSE)) {
mask |= HENVCFG_SSE;
}
} }
env->henvcfg = (env->henvcfg & ~mask) | (val & mask); env->henvcfg = (env->henvcfg & ~mask) | (val & mask);
@ -4966,6 +5015,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
/* Zcmt Extension */ /* Zcmt Extension */
[CSR_JVT] = {"jvt", zcmt, read_jvt, write_jvt}, [CSR_JVT] = {"jvt", zcmt, read_jvt, write_jvt},
/* zicfiss Extension, shadow stack register */
[CSR_SSP] = { "ssp", cfi_ss, read_ssp, write_ssp },
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
/* Machine Timers and Counters */ /* Machine Timers and Counters */
[CSR_MCYCLE] = { "mcycle", any, read_hpmcounter, [CSR_MCYCLE] = { "mcycle", any, read_hpmcounter,

View File

@ -368,6 +368,24 @@ static const VMStateDescription vmstate_elp = {
} }
}; };
static bool ssp_needed(void *opaque)
{
RISCVCPU *cpu = opaque;
return cpu->cfg.ext_zicfiss;
}
static const VMStateDescription vmstate_ssp = {
.name = "cpu/ssp",
.version_id = 1,
.minimum_version_id = 1,
.needed = ssp_needed,
.fields = (const VMStateField[]) {
VMSTATE_UINTTL(env.ssp, RISCVCPU),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_riscv_cpu = { const VMStateDescription vmstate_riscv_cpu = {
.name = "cpu", .name = "cpu",
.version_id = 10, .version_id = 10,
@ -441,6 +459,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_smstateen, &vmstate_smstateen,
&vmstate_jvt, &vmstate_jvt,
&vmstate_elp, &vmstate_elp,
&vmstate_ssp,
NULL NULL
} }
}; };