@@ -614,6 +614,19 @@ FIELD(TB_FLAGS, AXL, 26, 2)
FIELD(TB_FLAGS, FCFI_LP_EXPECTED, 28, 1)
/* zicfiss needs a TB flag so that correct TB is located based on tb flags */
FIELD(TB_FLAGS, BCFI_ENABLED, 29, 1)
+/*
+ * zicfiss shadow stack is special memory on which regular stores aren't
+ * allowed but shadow stack stores are allowed. Shadow stack stores can
+ * happen as `sspush` or `ssamoswap` instructions. `sspush` implicitly
+ * takes shadow stack address from CSR_SSP. But `ssamoswap` takes address
+ * from encoded input register and it will be used by supervisor software
+ * to access (read/write) user shadow stack for setting up rt_frame during
+ * signal delivery. Supervisor software will do so by setting SUM=1. Thus
+ * a TB flag is needed if SUM was 1 during TB generation to correctly
+ * reflect memory permissions to access shadow stack user memory from
+ * supervisor mode.
+ */
+FIELD(TB_FLAGS, SUM, 30, 1)
#ifdef TARGET_RISCV32
#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
@@ -180,6 +180,9 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
fs = EXT_STATUS_DIRTY;
vs = EXT_STATUS_DIRTY;
#else
+ flags = FIELD_DP32(flags, TB_FLAGS, SUM,
+ ((env->mstatus & MSTATUS_SUM) == MSTATUS_SUM));
+
flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
flags |= riscv_env_mmu_index(env, 0);
@@ -132,6 +132,10 @@ static bool trans_ssamoswap_w(DisasContext *ctx, arg_amoswap_w *a)
decode_save_opc(ctx);
src1 = get_address(ctx, a->rs1, 0);
+#ifndef CONFIG_USER_ONLY
+ /* Shadow stack access and thus index is SS TLB index */
+ ss_mmu_idx = get_ss_index(ctx);
+#endif
tcg_gen_atomic_xchg_tl(dest, src1, src2, ss_mmu_idx, (MO_ALIGN | MO_TESL));
gen_set_gpr(ctx, a->rd, dest);
@@ -224,6 +228,10 @@ static bool trans_ssamoswap_d(DisasContext *ctx, arg_amoswap_w *a)
decode_save_opc(ctx);
src1 = get_address(ctx, a->rs1, 0);
+#ifndef CONFIG_USER_ONLY
+ /* Shadow stack access and thus index is SS TLB index */
+ ss_mmu_idx = get_ss_index(ctx);
+#endif
tcg_gen_atomic_xchg_tl(dest, src1, src2, ss_mmu_idx, (MO_ALIGN | MO_TESQ));
gen_set_gpr(ctx, a->rd, dest);
@@ -32,6 +32,7 @@
* - S+SUM+2STAGE 0b110
* - Shadow stack+U 0b1000
* - Shadow stack+S 0b1001
+ * - Shadow stack+SUM 0b1010
*/
#define MMUIdx_U 0
#define MMUIdx_S 1
@@ -123,6 +123,8 @@ typedef struct DisasContext {
bool fcfi_lp_expected;
/* zicfiss extension, if shadow stack was enabled during TB gen */
bool bcfi_enabled;
+ /* SUM was on during tb translation? */
+ bool sum;
} DisasContext;
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -1128,6 +1130,29 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
return translator_ldl(env, &ctx->base, pc);
}
+#ifndef CONFIG_USER_ONLY
+static unsigned int get_ss_index(DisasContext *ctx)
+{
+ int ss_mmu_idx = MMU_IDX_SS_ACCESS;
+
+ /*
+ * If priv mode is S then a separate index for supervisor
+ * shadow stack accesses
+ */
+ if (ctx->priv == PRV_S) {
+ ss_mmu_idx |= MMUIdx_S;
+ }
+
+ /* If SUM was set, SS index should have S cleared */
+ if (ctx->sum) {
+ ss_mmu_idx &= ~(MMUIdx_S);
+ ss_mmu_idx |= MMUIdx_S_SUM;
+ }
+
+ return ss_mmu_idx;
+}
+#endif
+
/* Include insn module translation function */
#include "insn_trans/trans_rvi.c.inc"
#include "insn_trans/trans_rvm.c.inc"
Shadow stack instructions shadow stack mmu index for load/stores. `MMU_IDX_SS_ACCESS` at bit positon 3 is used as shadow stack index. Shadow stack mmu index depend on privilege and SUM bit. If shadow stack accesses happening in user mode, shadow stack mmu index = 0b1000. If shaodw stack access happening in supervisor mode mmu index = 0b1001. If shadow stack access happening in supervisor mode with SUM=1 then mmu index = 0b1010 Signed-off-by: Deepak Gupta <debug@rivosinc.com> --- target/riscv/cpu.h | 13 +++++++++++++ target/riscv/cpu_helper.c | 3 +++ target/riscv/insn_trans/trans_rva.c.inc | 8 ++++++++ target/riscv/internals.h | 1 + target/riscv/translate.c | 25 +++++++++++++++++++++++++ 5 files changed, 50 insertions(+)