* [PATCH v2 01/24] target/riscv: Add zicfilp extension
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 02/24] target/riscv: Introduce elp state and enabling controls for zicfilp Deepak Gupta
` (22 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
zicfilp [1] riscv cpu extension enables forward control flow integrity.
If enabled, all indirect calls must land on a landing pad instruction.
This patch sets up space for zicfilp extension in cpuconfig. zicfilp
is dependend on zicsr.
[1] - https://github.com/riscv/riscv-cfi
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>
---
target/riscv/cpu.c | 2 ++
target/riscv/cpu_cfg.h | 1 +
target/riscv/tcg/tcg-cpu.c | 5 +++++
3 files changed, 8 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 33ef4eb795..5dfb3f39ab 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -106,6 +106,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(ziccif, PRIV_VERSION_1_11_0, has_priv_1_11),
ISA_EXT_DATA_ENTRY(zicclsm, PRIV_VERSION_1_11_0, has_priv_1_11),
ISA_EXT_DATA_ENTRY(ziccrse, PRIV_VERSION_1_11_0, has_priv_1_11),
+ ISA_EXT_DATA_ENTRY(zicfilp, PRIV_VERSION_1_12_0, ext_zicfilp),
ISA_EXT_DATA_ENTRY(zicond, PRIV_VERSION_1_12_0, ext_zicond),
ISA_EXT_DATA_ENTRY(zicntr, PRIV_VERSION_1_12_0, ext_zicntr),
ISA_EXT_DATA_ENTRY(zicsr, PRIV_VERSION_1_10_0, ext_zicsr),
@@ -1472,6 +1473,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
/* Defaults for standard extensions */
MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false),
MULTI_EXT_CFG_BOOL("zifencei", ext_zifencei, true),
+ MULTI_EXT_CFG_BOOL("zicfilp", ext_zicfilp, false),
MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true),
MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true),
MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true),
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index 120905a254..88d5defbb5 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -67,6 +67,7 @@ struct RISCVCPUConfig {
bool ext_zicbom;
bool ext_zicbop;
bool ext_zicboz;
+ bool ext_zicfilp;
bool ext_zicond;
bool ext_zihintntl;
bool ext_zihintpause;
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index b8814ab753..ed19586c9d 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -623,6 +623,11 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
cpu->pmu_avail_ctrs = 0;
}
+ if (cpu->cfg.ext_zicfilp && !cpu->cfg.ext_zicsr) {
+ error_setg(errp, "zicfilp extension requires zicsr extension");
+ return;
+ }
+
/*
* Disable isa extensions based on priv spec after we
* validated and set everything we need.
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 02/24] target/riscv: Introduce elp state and enabling controls for zicfilp
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 01/24] target/riscv: Add zicfilp extension Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 03/24] target/riscv: save and restore elp state on priv transitions Deepak Gupta
` (21 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
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.
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>
---
target/riscv/cpu.c | 3 +++
target/riscv/cpu.h | 2 ++
target/riscv/cpu_bits.h | 12 ++++++++++++
target/riscv/csr.c | 31 +++++++++++++++++++++++++++++++
target/riscv/pmp.c | 5 +++++
target/riscv/pmp.h | 3 ++-
6 files changed, 55 insertions(+), 1 deletion(-)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5dfb3f39ab..82fa85a8d6 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 set to NO_LP_EXPECTED */
+ env->elp = NO_LP_EXPECTED;
+
/*
* 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..ae436a3179 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 */
+ cfi_elp 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..127f2179dc 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,12 +577,19 @@ 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
#define SSTATUS32_SD 0x80000000
#define SSTATUS64_SD 0x8000000000000000ULL
+/* enum for branch tracking state in cpu/hart */
+typedef enum {
+ NO_LP_EXPECTED = 0,
+ LP_EXPECTED = 1,
+} cfi_elp;
+
/* hstatus CSR bits */
#define HSTATUS_VSBE 0x00000020
#define HSTATUS_GVA 0x00000040
@@ -747,6 +756,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 +770,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/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
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 03/24] target/riscv: save and restore elp state on priv transitions
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 01/24] target/riscv: Add zicfilp extension Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 02/24] target/riscv: Introduce elp state and enabling controls for zicfilp Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 23:04 ` Richard Henderson
2024-07-29 17:53 ` [PATCH v2 04/24] target/riscv: additional code information for sw check Deepak Gupta
` (20 subsequent siblings)
23 siblings, 1 reply; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
elp state is recorded in *status on trap entry (less privilege to higher
privilege) and restored in elp from *status on trap exit (higher to less
privilege).
Additionally this patch introduces a forward cfi helper function to
determine if current privilege has forward cfi is enabled or not based on
*envcfg (for U, VU, S, VU, HS) or mseccfg csr (for M). For qemu-user, a
new field `ufcfien` is introduced which is by default set to false and
helper function returns value deposited in `ufcfien` for qemu-user.
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>
---
target/riscv/cpu.c | 5 ++++
target/riscv/cpu.h | 2 ++
target/riscv/cpu_helper.c | 58 +++++++++++++++++++++++++++++++++++++++
target/riscv/op_helper.c | 18 ++++++++++++
4 files changed, 83 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 82fa85a8d6..e1526c7ab5 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1022,6 +1022,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
env->load_res = -1;
set_default_nan_mode(1, &env->fp_status);
+#ifdef CONFIG_USER_ONLY
+ /* qemu-user for riscv, fcfi is off by default */
+ env->ufcfien = false;
+#endif
+
#ifndef CONFIG_USER_ONLY
if (cpu->cfg.debug) {
riscv_trigger_reset_hold(env);
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index ae436a3179..8c7841fc08 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -226,6 +226,7 @@ struct CPUArchState {
cfi_elp elp;
#ifdef CONFIG_USER_ONLY
uint32_t elf_flags;
+ bool ufcfien;
#endif
#ifndef CONFIG_USER_ONLY
@@ -530,6 +531,7 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen);
bool riscv_cpu_vector_enabled(CPURISCVState *env);
void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch);
+bool cpu_get_fcfien(CPURISCVState *env);
G_NORETURN void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 6709622dd3..fb4b6066d3 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -33,6 +33,7 @@
#include "cpu_bits.h"
#include "debug.h"
#include "tcg/oversized-guest.h"
+#include "pmp.h"
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch)
{
@@ -63,6 +64,35 @@ int riscv_env_mmu_index(CPURISCVState *env, bool ifetch)
#endif
}
+bool cpu_get_fcfien(CPURISCVState *env)
+{
+#ifdef CONFIG_USER_ONLY
+ return env->ufcfien;
+#else
+ /* no cfi extension, return false */
+ if (!env_archcpu(env)->cfg.ext_zicfilp) {
+ return false;
+ }
+
+ switch (env->priv) {
+ case PRV_U:
+ if (riscv_has_ext(env, RVS)) {
+ return (env->senvcfg & MENVCFG_LPE) ? true : false;
+ }
+ return (env->menvcfg & MENVCFG_LPE) ? true : false;
+ case PRV_S:
+ if (env->virt_enabled) {
+ return (env->henvcfg & HENVCFG_LPE) ? true : false;
+ }
+ return (env->menvcfg & MENVCFG_LPE) ? true : false;
+ case PRV_M:
+ return (env->mseccfg & MSECCFG_MLPE) ? true : false;
+ default:
+ g_assert_not_reached();
+ }
+#endif
+}
+
void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
uint64_t *cs_base, uint32_t *pflags)
{
@@ -546,6 +576,15 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
}
bool current_virt = env->virt_enabled;
+ /*
+ * If zicfilp extension available and henvcfg.LPE = 1,
+ * then apply SPELP mask on mstatus
+ */
+ if (env_archcpu(env)->cfg.ext_zicfilp &&
+ get_field(env->henvcfg, HENVCFG_LPE)) {
+ mstatus_mask |= SSTATUS_SPELP;
+ }
+
g_assert(riscv_has_ext(env, RVH));
if (current_virt) {
@@ -1754,6 +1793,11 @@ void riscv_cpu_do_interrupt(CPUState *cs)
if (env->priv <= PRV_S && cause < 64 &&
(((deleg >> cause) & 1) || s_injected || vs_injected)) {
/* handle the trap in S-mode */
+ /* save elp status */
+ if (cpu_get_fcfien(env)) {
+ env->mstatus = set_field(env->mstatus, MSTATUS_SPELP, env->elp);
+ }
+
if (riscv_has_ext(env, RVH)) {
uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
@@ -1802,6 +1846,11 @@ void riscv_cpu_do_interrupt(CPUState *cs)
riscv_cpu_set_mode(env, PRV_S);
} else {
/* handle the trap in M-mode */
+ /* save elp status */
+ if (cpu_get_fcfien(env)) {
+ env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, env->elp);
+ }
+
if (riscv_has_ext(env, RVH)) {
if (env->virt_enabled) {
riscv_cpu_swap_hypervisor_regs(env);
@@ -1833,6 +1882,15 @@ void riscv_cpu_do_interrupt(CPUState *cs)
riscv_cpu_set_mode(env, PRV_M);
}
+ /*
+ * Interrupt/exception/trap delivery is asynchronous event and as per
+ * Zisslpcfi spec CPU should clear up the ELP state. If cfi extension is
+ * available, clear ELP state.
+ */
+
+ if (cpu->cfg.ext_zicfilp) {
+ env->elp = NO_LP_EXPECTED;
+ }
/*
* NOTE: it is not necessary to yield load reservations here. It is only
* necessary for an SC from "another hart" to cause a load reservation
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 2baf5bc3ca..488116cc2e 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -313,6 +313,15 @@ target_ulong helper_sret(CPURISCVState *env)
riscv_cpu_set_mode(env, prev_priv);
+ /*
+ * If forward cfi enabled for new priv, restore elp status
+ * and clear spelp in mstatus
+ */
+ if (cpu_get_fcfien(env)) {
+ env->elp = get_field(env->mstatus, MSTATUS_SPELP);
+ env->mstatus = set_field(env->mstatus, MSTATUS_SPELP, 0);
+ }
+
return retpc;
}
@@ -357,6 +366,15 @@ target_ulong helper_mret(CPURISCVState *env)
riscv_cpu_set_virt_enabled(env, prev_virt);
}
+ /*
+ * If forward cfi enabled for new priv, restore elp status
+ * and clear mpelp in mstatus
+ */
+ if (cpu_get_fcfien(env)) {
+ env->elp = get_field(env->mstatus, MSTATUS_MPELP);
+ env->mstatus = set_field(env->mstatus, MSTATUS_MPELP, 0);
+ }
+
return retpc;
}
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH v2 03/24] target/riscv: save and restore elp state on priv transitions
2024-07-29 17:53 ` [PATCH v2 03/24] target/riscv: save and restore elp state on priv transitions Deepak Gupta
@ 2024-07-29 23:04 ` Richard Henderson
2024-07-29 23:33 ` Deepak Gupta
0 siblings, 1 reply; 35+ messages in thread
From: Richard Henderson @ 2024-07-29 23:04 UTC (permalink / raw)
To: Deepak Gupta, qemu-riscv, qemu-devel, jim.shu, andy.chiu,
jesse.huang, kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu
On 7/30/24 03:53, Deepak Gupta wrote:
> elp state is recorded in *status on trap entry (less privilege to higher
> privilege) and restored in elp from *status on trap exit (higher to less
> privilege).
>
> Additionally this patch introduces a forward cfi helper function to
> determine if current privilege has forward cfi is enabled or not based on
> *envcfg (for U, VU, S, VU, HS) or mseccfg csr (for M). For qemu-user, a
> new field `ufcfien` is introduced which is by default set to false and
> helper function returns value deposited in `ufcfien` for qemu-user.
Why are you using a different field for qemu-user?
Much better to simply configure menvcfg the same as for system mode.
> + return (env->menvcfg & MENVCFG_LPE) ? true : false;
Never use ?: with true/false. Use the correct boolean expression in the first place,
which in this case is just the & expression.
r~
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v2 03/24] target/riscv: save and restore elp state on priv transitions
2024-07-29 23:04 ` Richard Henderson
@ 2024-07-29 23:33 ` Deepak Gupta
0 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 23:33 UTC (permalink / raw)
To: Richard Henderson
Cc: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng, palmer, Alistair.Francis, laurent, bmeng.cn,
liwei1518, dbarboza, zhiwei_liu
Thanks Richard.
On Tue, Jul 30, 2024 at 09:04:29AM +1000, Richard Henderson wrote:
>On 7/30/24 03:53, Deepak Gupta wrote:
>>elp state is recorded in *status on trap entry (less privilege to higher
>>privilege) and restored in elp from *status on trap exit (higher to less
>>privilege).
>>
>>Additionally this patch introduces a forward cfi helper function to
>>determine if current privilege has forward cfi is enabled or not based on
>>*envcfg (for U, VU, S, VU, HS) or mseccfg csr (for M). For qemu-user, a
>>new field `ufcfien` is introduced which is by default set to false and
>>helper function returns value deposited in `ufcfien` for qemu-user.
>
>Why are you using a different field for qemu-user?
>Much better to simply configure menvcfg the same as for system mode.
I am assuming `CONFIG_USER_ONLY` is set for qemu-user builds and unset
for `not qemu-user` builds. Let me know if I got that right?
`menvcfg` (and a lot of other system related fields CPUArchstate for riscv)
are wrapped under `#ifndef CONFIG_USER_ONLY`. So `menvcfg` field is not
available for qemu-user compile.
>
>
>>+ return (env->menvcfg & MENVCFG_LPE) ? true : false;
>
>Never use ?: with true/false. Use the correct boolean expression in
>the first place, which in this case is just the & expression.
Noted.
Will fix this and other instances in patch series.
>
>
>r~
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v2 04/24] target/riscv: additional code information for sw check
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (2 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 03/24] target/riscv: save and restore elp state on priv transitions Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp Deepak Gupta
` (19 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
sw check exception support was recently added. This patch further augments
sw check exception by providing support for additional code which is
provided in *tval. Adds `sw_check_code` field in cpuarchstate. Whenever
sw check exception is raised *tval gets the value deposited in
`sw_check_code`.
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
target/riscv/cpu.h | 2 ++
target/riscv/cpu_helper.c | 2 ++
target/riscv/csr.c | 1 +
3 files changed, 5 insertions(+)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 8c7841fc08..12334f9540 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -224,6 +224,8 @@ struct CPUArchState {
/* elp state for zicfilp extension */
cfi_elp elp;
+ /* sw check code for sw check exception */
+ target_ulong sw_check_code;
#ifdef CONFIG_USER_ONLY
uint32_t elf_flags;
bool ufcfien;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index fb4b6066d3..41bc73ad60 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1762,6 +1762,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
cs->watchpoint_hit = NULL;
}
break;
+ case RISCV_EXCP_SW_CHECK:
+ tval = env->sw_check_code;
default:
break;
}
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 5771a14848..a5a969a377 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1179,6 +1179,7 @@ static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
(1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) | \
(1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) | \
(1ULL << (RISCV_EXCP_STORE_PAGE_FAULT)) | \
+ (1ULL << (RISCV_EXCP_SW_CHECK)) | \
(1ULL << (RISCV_EXCP_INST_GUEST_PAGE_FAULT)) | \
(1ULL << (RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT)) | \
(1ULL << (RISCV_EXCP_VIRT_INSTRUCTION_FAULT)) | \
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (3 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 04/24] target/riscv: additional code information for sw check Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 23:15 ` Richard Henderson
2024-07-29 17:53 ` [PATCH v2 06/24] target/riscv: zicfilp `lpad` impl and branch tracking Deepak Gupta
` (18 subsequent siblings)
23 siblings, 1 reply; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
zicfilp protects forward control flow (if enabled) by enforcing all
indirect call and jmp must land on a landing pad instruction `lpad`. If
target of an indirect call or jmp is not `lpad` then cpu/hart must raise
a sw check exception with tval = 2.
This patch implements the mechanism using TCG. Target architecture branch
instruction must define the end of a TB. Using this property, during
translation of branch instruction, TB flag = FCFI_LP_EXPECTED can be set.
Translation of target TB can check if FCFI_LP_EXPECTED flag is set and a
flag (fcfi_lp_expected) can be set in DisasContext. If `lpad` gets
translated, fcfi_lp_expected flag in DisasContext can be cleared. Else
it'll fault.
This patch also also adds flag for forward cfi in DisasContext.
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>
---
target/riscv/cpu.h | 2 ++
target/riscv/cpu_bits.h | 3 +++
target/riscv/cpu_helper.c | 12 ++++++++++
target/riscv/translate.c | 48 +++++++++++++++++++++++++++++++++++++++
4 files changed, 65 insertions(+)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 12334f9540..7fed5d2750 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -606,6 +606,8 @@ FIELD(TB_FLAGS, ITRIGGER, 22, 1)
FIELD(TB_FLAGS, VIRT_ENABLED, 23, 1)
FIELD(TB_FLAGS, PRIV, 24, 2)
FIELD(TB_FLAGS, AXL, 26, 2)
+/* zicfilp needs a TB flag to track indirect branches */
+FIELD(TB_FLAGS, FCFI_LP_EXPECTED, 28, 1)
#ifdef TARGET_RISCV32
#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 127f2179dc..477e24feaf 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -691,6 +691,9 @@ typedef enum RISCVException {
RISCV_EXCP_SEMIHOST = 0x3f,
} RISCVException;
+/* zicfilp defines lp violation results in sw check with tval = 2*/
+#define RISCV_EXCP_SW_CHECK_FCFI_TVAL 2
+
#define RISCV_EXCP_INT_FLAG 0x80000000
#define RISCV_EXCP_INT_MASK 0x7fffffff
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 41bc73ad60..2cb1d45467 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -134,6 +134,18 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1);
}
+ if (cpu_get_fcfien(env)) {
+ /*
+ * For Forward CFI, only the expectation of a lpcll at
+ * the start of the block is tracked (which can only happen
+ * when FCFI is enabled for the current processor mode). A jump
+ * or call at the end of the previous TB will have updated
+ * env->elp to indicate the expectation.
+ */
+ flags = FIELD_DP32(flags, TB_FLAGS, FCFI_LP_EXPECTED,
+ env->elp != NO_LP_EXPECTED);
+ }
+
#ifdef CONFIG_USER_ONLY
fs = EXT_STATUS_DIRTY;
vs = EXT_STATUS_DIRTY;
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index acba90f170..c746d7df08 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -20,6 +20,7 @@
#include "qemu/log.h"
#include "cpu.h"
#include "tcg/tcg-op.h"
+#include "tcg/tcg-temp-internal.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@@ -44,6 +45,7 @@ static TCGv load_val;
/* globals for PM CSRs */
static TCGv pm_mask;
static TCGv pm_base;
+static TCGOp *cfi_lp_check;
/*
* If an operation is being performed on less than TARGET_LONG_BITS,
@@ -116,6 +118,9 @@ typedef struct DisasContext {
bool frm_valid;
bool insn_start_updated;
const GPtrArray *decoders;
+ /* zicfilp extension. cfi enabled or not. lp expected or not */
+ bool fcfi_enabled;
+ bool fcfi_lp_expected;
} DisasContext;
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -1238,6 +1243,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED);
ctx->ztso = cpu->cfg.ext_ztso;
ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER);
+ ctx->fcfi_lp_expected = FIELD_EX32(tb_flags, TB_FLAGS, FCFI_LP_EXPECTED);
+ ctx->fcfi_enabled = cpu_get_fcfien(env) && ctx->fcfi_lp_expected;
ctx->zero = tcg_constant_tl(0);
ctx->virt_inst_excp = false;
ctx->decoders = cpu->decoders;
@@ -1245,6 +1252,39 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
{
+ DisasContext *ctx = container_of(db, DisasContext, base);
+
+ if (ctx->fcfi_lp_expected) {
+ /*
+ * Since we can't look ahead to confirm that the first
+ * instruction is a legal landing pad instruction, emit
+ * compare-and-branch sequence that will be fixed-up in
+ * riscv_tr_tb_stop() to either statically hit or skip an
+ * illegal instruction exception depending on whether the
+ * flag was lowered by translation of a CJLP or JLP as
+ * the first instruction in the block.
+ */
+ TCGv_i32 immediate;
+ TCGLabel *l;
+ l = gen_new_label();
+ immediate = tcg_temp_new_i32();
+ tcg_gen_movi_i32(immediate, 0);
+ cfi_lp_check = tcg_last_op();
+ tcg_gen_brcondi_i32(TCG_COND_EQ, immediate, 0, l);
+ tcg_temp_free_i32(immediate);
+ tcg_gen_st_tl(
+ tcg_constant_tl(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
+ tcg_env, offsetof(CPURISCVState, sw_check_code));
+ generate_exception(ctx, RISCV_EXCP_SW_CHECK);
+ gen_set_label(l);
+ /*
+ * Despite the use of gen_exception_illegal(), the rest of
+ * the TB needs to be generated. The TCG optimizer will
+ * clean things up depending on which path ends up being
+ * active.
+ */
+ ctx->base.is_jmp = DISAS_NEXT;
+ }
}
static void riscv_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
@@ -1303,6 +1343,14 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
default:
g_assert_not_reached();
}
+
+ if (ctx->fcfi_lp_expected) {
+ /*
+ * If the "lp expected" flag is still up, the block needs to take an
+ * illegal instruction exception.
+ */
+ tcg_set_insn_param(cfi_lp_check, 1, tcgv_i32_arg(tcg_constant_i32(1)));
+ }
}
static const TranslatorOps riscv_tr_ops = {
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp
2024-07-29 17:53 ` [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp Deepak Gupta
@ 2024-07-29 23:15 ` Richard Henderson
2024-08-01 6:59 ` Deepak Gupta
0 siblings, 1 reply; 35+ messages in thread
From: Richard Henderson @ 2024-07-29 23:15 UTC (permalink / raw)
To: qemu-devel
On 7/30/24 03:53, Deepak Gupta wrote:
> diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> index acba90f170..c746d7df08 100644
> --- a/target/riscv/translate.c
> +++ b/target/riscv/translate.c
> @@ -20,6 +20,7 @@
> #include "qemu/log.h"
> #include "cpu.h"
> #include "tcg/tcg-op.h"
> +#include "tcg/tcg-temp-internal.h"
No, this is internal to tcg, as the filename says.
> #include "exec/exec-all.h"
> #include "exec/helper-proto.h"
> #include "exec/helper-gen.h"
> @@ -44,6 +45,7 @@ static TCGv load_val;
> /* globals for PM CSRs */
> static TCGv pm_mask;
> static TCGv pm_base;
> +static TCGOp *cfi_lp_check;
>
> /*
> * If an operation is being performed on less than TARGET_LONG_BITS,
> @@ -116,6 +118,9 @@ typedef struct DisasContext {
> bool frm_valid;
> bool insn_start_updated;
> const GPtrArray *decoders;
> + /* zicfilp extension. cfi enabled or not. lp expected or not */
> + bool fcfi_enabled;
> + bool fcfi_lp_expected;
> } DisasContext;
>
> static inline bool has_ext(DisasContext *ctx, uint32_t ext)
> @@ -1238,6 +1243,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED);
> ctx->ztso = cpu->cfg.ext_ztso;
> ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER);
> + ctx->fcfi_lp_expected = FIELD_EX32(tb_flags, TB_FLAGS, FCFI_LP_EXPECTED);
> + ctx->fcfi_enabled = cpu_get_fcfien(env) && ctx->fcfi_lp_expected;
This is incorrect. You cannot check fcfien like this here; you must place it in a tb flag
like "lp_expected".
> @@ -1245,6 +1252,39 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
>
> static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
> {
> + DisasContext *ctx = container_of(db, DisasContext, base);
> +
> + if (ctx->fcfi_lp_expected) {
> + /*
> + * Since we can't look ahead to confirm that the first
> + * instruction is a legal landing pad instruction, emit
> + * compare-and-branch sequence that will be fixed-up in
> + * riscv_tr_tb_stop() to either statically hit or skip an
> + * illegal instruction exception depending on whether the
> + * flag was lowered by translation of a CJLP or JLP as
> + * the first instruction in the block.
> + */
> + TCGv_i32 immediate;
> + TCGLabel *l;
> + l = gen_new_label();
> + immediate = tcg_temp_new_i32();
> + tcg_gen_movi_i32(immediate, 0);
> + cfi_lp_check = tcg_last_op();
> + tcg_gen_brcondi_i32(TCG_COND_EQ, immediate, 0, l);
> + tcg_temp_free_i32(immediate);
> + tcg_gen_st_tl(
> + tcg_constant_tl(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
> + tcg_env, offsetof(CPURISCVState, sw_check_code));
> + generate_exception(ctx, RISCV_EXCP_SW_CHECK);
> + gen_set_label(l);
> + /*
> + * Despite the use of gen_exception_illegal(), the rest of
> + * the TB needs to be generated. The TCG optimizer will
> + * clean things up depending on which path ends up being
> + * active.
> + */
> + ctx->base.is_jmp = DISAS_NEXT;
> + }
> }
Better to simply delay the check to the first insn load.
See aarch64_tr_translate_insn, dc_isar_feature(aa64_bti, s).
r~
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp
2024-07-29 23:15 ` Richard Henderson
@ 2024-08-01 6:59 ` Deepak Gupta
2024-08-01 9:12 ` Richard Henderson
0 siblings, 1 reply; 35+ messages in thread
From: Deepak Gupta @ 2024-08-01 6:59 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
On Mon, Jul 29, 2024 at 7:34 PM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 7/30/24 03:53, Deepak Gupta wrote:
> > diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> > index acba90f170..c746d7df08 100644
> > --- a/target/riscv/translate.c
> > +++ b/target/riscv/translate.c
> > @@ -20,6 +20,7 @@
> > #include "qemu/log.h"
> > #include "cpu.h"
> > #include "tcg/tcg-op.h"
> > +#include "tcg/tcg-temp-internal.h"
>
> No, this is internal to tcg, as the filename says.
Ok
>
>
> > #include "exec/exec-all.h"
> > #include "exec/helper-proto.h"
> > #include "exec/helper-gen.h"
> > @@ -44,6 +45,7 @@ static TCGv load_val;
> > /* globals for PM CSRs */
> > static TCGv pm_mask;
> > static TCGv pm_base;
> > +static TCGOp *cfi_lp_check;
> >
> > /*
> > * If an operation is being performed on less than TARGET_LONG_BITS,
> > @@ -116,6 +118,9 @@ typedef struct DisasContext {
> > bool frm_valid;
> > bool insn_start_updated;
> > const GPtrArray *decoders;
> > + /* zicfilp extension. cfi enabled or not. lp expected or not */
> > + bool fcfi_enabled;
> > + bool fcfi_lp_expected;
> > } DisasContext;
> >
> > static inline bool has_ext(DisasContext *ctx, uint32_t ext)
> > @@ -1238,6 +1243,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> > ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED);
> > ctx->ztso = cpu->cfg.ext_ztso;
> > ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER);
> > + ctx->fcfi_lp_expected = FIELD_EX32(tb_flags, TB_FLAGS, FCFI_LP_EXPECTED);
> > + ctx->fcfi_enabled = cpu_get_fcfien(env) && ctx->fcfi_lp_expected;
>
> This is incorrect. You cannot check fcfien like this here; you must place it in a tb flag
> like "lp_expected".
hmm... you've suggested below to use `aarch64_tr_translate_insn` and
check if it's the first instruction.
and put the check there.
In that case I won't need FCFI_LP_EXPECTED TB flag.
Then I would rather use it as FCFI_ENABLED TB flag.
>
>
> > @@ -1245,6 +1252,39 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> >
> > static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu)
> > {
> > + DisasContext *ctx = container_of(db, DisasContext, base);
> > +
> > + if (ctx->fcfi_lp_expected) {
> > + /*
> > + * Since we can't look ahead to confirm that the first
> > + * instruction is a legal landing pad instruction, emit
> > + * compare-and-branch sequence that will be fixed-up in
> > + * riscv_tr_tb_stop() to either statically hit or skip an
> > + * illegal instruction exception depending on whether the
> > + * flag was lowered by translation of a CJLP or JLP as
> > + * the first instruction in the block.
> > + */
> > + TCGv_i32 immediate;
> > + TCGLabel *l;
> > + l = gen_new_label();
> > + immediate = tcg_temp_new_i32();
> > + tcg_gen_movi_i32(immediate, 0);
> > + cfi_lp_check = tcg_last_op();
> > + tcg_gen_brcondi_i32(TCG_COND_EQ, immediate, 0, l);
> > + tcg_temp_free_i32(immediate);
> > + tcg_gen_st_tl(
> > + tcg_constant_tl(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
> > + tcg_env, offsetof(CPURISCVState, sw_check_code));
> > + generate_exception(ctx, RISCV_EXCP_SW_CHECK);
> > + gen_set_label(l);
> > + /*
> > + * Despite the use of gen_exception_illegal(), the rest of
> > + * the TB needs to be generated. The TCG optimizer will
> > + * clean things up depending on which path ends up being
> > + * active.
> > + */
> > + ctx->base.is_jmp = DISAS_NEXT;
> > + }
> > }
>
> Better to simply delay the check to the first insn load.
> See aarch64_tr_translate_insn, dc_isar_feature(aa64_bti, s).
Hmmm...
Thanks, I think it'll probably make it simpler.
Let me re-work this logic and test it out if it works.
>
>
> r~
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp
2024-08-01 6:59 ` Deepak Gupta
@ 2024-08-01 9:12 ` Richard Henderson
2024-08-01 17:05 ` Deepak Gupta
0 siblings, 1 reply; 35+ messages in thread
From: Richard Henderson @ 2024-08-01 9:12 UTC (permalink / raw)
To: Deepak Gupta; +Cc: qemu-devel
On 8/1/24 16:59, Deepak Gupta wrote:
> hmm... you've suggested below to use `aarch64_tr_translate_insn` and
> check if it's the first instruction.
> and put the check there.
> In that case I won't need FCFI_LP_EXPECTED TB flag.
> Then I would rather use it as FCFI_ENABLED TB flag.
You will need both bits.
r~
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp
2024-08-01 9:12 ` Richard Henderson
@ 2024-08-01 17:05 ` Deepak Gupta
2024-08-01 21:34 ` Richard Henderson
0 siblings, 1 reply; 35+ messages in thread
From: Deepak Gupta @ 2024-08-01 17:05 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel
On Thu, Aug 1, 2024 at 2:12 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 8/1/24 16:59, Deepak Gupta wrote:
> > hmm... you've suggested below to use `aarch64_tr_translate_insn` and
> > check if it's the first instruction.
> > and put the check there.
> > In that case I won't need FCFI_LP_EXPECTED TB flag.
> > Then I would rather use it as FCFI_ENABLED TB flag.
>
> You will need both bits.
I was thinking of following logic and wanted to run by you to check if
I am missing something
obvious.
---Recording fcfi_enabled in disascontext---
Add a FCFI_ENABLED TB flag which gets set (or not set) in `cpu_get_tb_cpu_state`
And `riscv_tr_init_disas_context` does
DisasContext->fcfi_enabled = extracts FCFI_ENABLED TB flag.
---Set elp on translation of indirect jump/call----
translation for jalr (instruction which triggers elp state) does following
trans_jalr:
if (DisasContext->fcfi_enabled)
env->elp = LP_EXPECTED
---Check if first instruction is not a landing pad----
In `riscv_tr_translate_insn`
if (first instruction of TB && env->elp) {
if (`insn` is not a `lpad` (landing pad) encoding)
raise_exception();
}
---label check embedded in landing pad instruction---
In `trans_lpad`
env->elp = NO_LP_EXPECTED
invoke a helper which will check embedded label value against value in
ISA defined register (x7)
I think this will work with just one TB flag (FCFI_ENABLED). Let me
know if I am missing something.
>
>
> r~
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp
2024-08-01 17:05 ` Deepak Gupta
@ 2024-08-01 21:34 ` Richard Henderson
0 siblings, 0 replies; 35+ messages in thread
From: Richard Henderson @ 2024-08-01 21:34 UTC (permalink / raw)
To: Deepak Gupta; +Cc: qemu-devel
On 8/2/24 03:05, Deepak Gupta wrote:
> On Thu, Aug 1, 2024 at 2:12 AM Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> On 8/1/24 16:59, Deepak Gupta wrote:
>>> hmm... you've suggested below to use `aarch64_tr_translate_insn` and
>>> check if it's the first instruction.
>>> and put the check there.
>>> In that case I won't need FCFI_LP_EXPECTED TB flag.
>>> Then I would rather use it as FCFI_ENABLED TB flag.
>>
>> You will need both bits.
>
> I was thinking of following logic and wanted to run by you to check if
> I am missing something
> obvious.
>
> ---Recording fcfi_enabled in disascontext---
> Add a FCFI_ENABLED TB flag which gets set (or not set) in `cpu_get_tb_cpu_state`
>
> And `riscv_tr_init_disas_context` does
> DisasContext->fcfi_enabled = extracts FCFI_ENABLED TB flag.
>
>
> ---Set elp on translation of indirect jump/call----
> translation for jalr (instruction which triggers elp state) does following
>
> trans_jalr:
> if (DisasContext->fcfi_enabled)
> env->elp = LP_EXPECTED
>
> ---Check if first instruction is not a landing pad----
> In `riscv_tr_translate_insn`
>
> if (first instruction of TB && env->elp) {
You can't access env->elp during translation like this.
That's why you need either
(1) the LP_EXPECTED bit in tb_flags as well, or
(2) a runtime test against elp.
> if (`insn` is not a `lpad` (landing pad) encoding)
> raise_exception();
> }
>
> ---label check embedded in landing pad instruction---
> In `trans_lpad`
>
> env->elp = NO_LP_EXPECTED
> invoke a helper which will check embedded label value against value in
> ISA defined register (x7)
You don't need a helper for such a trivial operation.
tcg_gen_extract_tl(tmp, get_gpr(ctx, 7, EXT_NONE), 12, 20);
tcg_gen_brcondi_tl(TCG_COND_EQ, tmp, a->imm, skip);
generate_exception(...);
r~
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v2 06/24] target/riscv: zicfilp `lpad` impl and branch tracking
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (4 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 05/24] target/riscv: tracking indirect branches (fcfi) for zicfilp Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 07/24] disas/riscv: enabled `lpad` disassembly Deepak Gupta
` (17 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Implements setting lp expected when `jalr` is encountered and implements
`lpad` instruction of zicfilp. `lpad` instruction is taken out of
auipc x0, <imm_20>. This is an existing HINTNOP space. If `lpad` is
target of an indirect branch, cpu checks for 20 bit value in x7 upper
with 20 bit value embedded in `lpad`. If they don't match, cpu raises a
sw check exception with tval = 2.
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>
---
target/riscv/cpu_user.h | 1 +
target/riscv/helper.h | 4 ++
target/riscv/insn32.decode | 6 ++-
target/riscv/insn_trans/trans_rvi.c.inc | 51 +++++++++++++++++++++++++
target/riscv/op_helper.c | 32 ++++++++++++++++
5 files changed, 93 insertions(+), 1 deletion(-)
diff --git a/target/riscv/cpu_user.h b/target/riscv/cpu_user.h
index 02afad608b..e6927ff847 100644
--- a/target/riscv/cpu_user.h
+++ b/target/riscv/cpu_user.h
@@ -15,5 +15,6 @@
#define xA6 16
#define xA7 17 /* syscall number for RVI ABI */
#define xT0 5 /* syscall number for RVE ABI */
+#define xT2 7
#endif
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 451261ce5a..ab55bbbf73 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -121,6 +121,10 @@ DEF_HELPER_2(cbo_clean_flush, void, env, tl)
DEF_HELPER_2(cbo_inval, void, env, tl)
DEF_HELPER_2(cbo_zero, void, env, tl)
+/* Forward CFI label checking */
+DEF_HELPER_2(cfi_jalr, void, env, int)
+DEF_HELPER_2(cfi_check_landing_pad, void, env, int)
+
/* Special functions */
DEF_HELPER_2(csrr, tl, env, int)
DEF_HELPER_3(csrw, void, env, int, tl)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index c45b8fa1d8..c963c59c8e 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -40,6 +40,7 @@
%imm_z6 26:1 15:5
%imm_mop5 30:1 26:2 20:2
%imm_mop3 30:1 26:2
+%imm_cfi20 12:20
# Argument sets:
&empty
@@ -123,7 +124,10 @@ sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm
# *** RV32I Base Instruction Set ***
lui .................... ..... 0110111 @u
-auipc .................... ..... 0010111 @u
+{
+ lpad .................... 00000 0010111 %imm_cfi20
+ auipc .................... ..... 0010111 @u
+}
jal .................... ..... 1101111 @j
jalr ............ ..... 000 ..... 1100111 @i
beq ....... ..... ..... 000 ..... 1100011 @b
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index 98e3806d5e..ee868c5fcb 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -36,6 +36,44 @@ static bool trans_lui(DisasContext *ctx, arg_lui *a)
return true;
}
+static bool trans_lpad(DisasContext *ctx, arg_lpad *a)
+{
+ /* zicfilp only supported on 32bit and 64bit */
+ if (get_xl(ctx) != MXL_RV32 && get_xl(ctx) != MXL_RV64) {
+ return false;
+ }
+
+ /* forward cfi not enabled, return false */
+ if (!ctx->fcfi_enabled) {
+ return false;
+ }
+
+ /*
+ * If this is the first instruction of the TB, let the translator
+ * know the landing pad requirement was satisfied. No need to bother
+ * checking for CFI feature or enablement.
+ */
+
+ if (ctx->base.pc_next == ctx->base.pc_first) {
+ ctx->fcfi_lp_expected = false;
+ /* PC must be 4 byte aligned */
+ if (ctx->fcfi_enabled && ((ctx->base.pc_next) & 0x3)) {
+ /*
+ * misaligned, according to spec we should raise sw check exception
+ */
+ tcg_gen_st_tl(
+ tcg_constant_tl(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
+ tcg_env, offsetof(CPURISCVState, sw_check_code));
+ generate_exception(ctx, RISCV_EXCP_SW_CHECK);
+ return true;
+ }
+ }
+
+ /* use helper to do label check */
+ gen_helper_cfi_check_landing_pad(tcg_env, tcg_constant_i32(a->imm_cfi20));
+ return true;
+}
+
static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
{
TCGv target_pc = dest_gpr(ctx, a->rd);
@@ -75,6 +113,19 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a)
gen_set_gpr(ctx, a->rd, succ_pc);
tcg_gen_mov_tl(cpu_pc, target_pc);
+ if (ctx->cfg_ptr->ext_zicfilp) {
+ /*
+ * Rely on a helper to check the forward CFI enable for the
+ * current process mode. The alternatives would be (1) include
+ * "fcfi enabled" in the cflags or (2) maintain a "fcfi
+ * currently enabled" in tcg_env and emit TCG code to access
+ * and test it.
+ */
+ if (a->rs1 != xRA && a->rs1 != xT0 && a->rs1 != xT2) {
+ gen_helper_cfi_jalr(tcg_env, tcg_constant_i32(LP_EXPECTED));
+ }
+ }
+
lookup_and_goto_ptr(ctx);
if (misaligned) {
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 488116cc2e..2d152f0a00 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -259,6 +259,38 @@ void helper_cbo_inval(CPURISCVState *env, target_ulong address)
/* We don't emulate the cache-hierarchy, so we're done. */
}
+void helper_cfi_jalr(CPURISCVState *env, int elp)
+{
+ /*
+ * The translation routine doesn't know if forward CFI is enabled
+ * in the current processor mode or not. It's not worth burning a
+ * cflags bit to encode this, or tracking the current-mode-fcfi
+ * enable in a dedicated member of 'env'. Just come out to a helper
+ * for jump/call on a core with CFI.
+ */
+ if (cpu_get_fcfien(env)) {
+ env->elp = elp;
+ }
+}
+
+void helper_cfi_check_landing_pad(CPURISCVState *env, int lbl)
+{
+ if ((env->elp == LP_EXPECTED) && cpu_get_fcfien(env)) {
+ /*
+ * Check for the 20bit label match. We already checked 4 byte
+ * alignment in tcg
+ * High 20bits (b31:12) in x7/t2 hold label. We need drop bits
+ * greater than 31 and then shift 12 right
+ */
+ if (lbl && (lbl != ((env->gpr[xT2] & 0xFFFFFFFF) >> 12))) {
+ env->sw_check_code = RISCV_EXCP_SW_CHECK_FCFI_TVAL;
+ riscv_raise_exception(env, RISCV_EXCP_SW_CHECK, GETPC());
+ }
+
+ env->elp = NO_LP_EXPECTED;
+ }
+}
+
#ifndef CONFIG_USER_ONLY
target_ulong helper_sret(CPURISCVState *env)
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 07/24] disas/riscv: enabled `lpad` disassembly
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (5 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 06/24] target/riscv: zicfilp `lpad` impl and branch tracking Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 08/24] linux-user/syscall: introduce prctl for indirect branch tracking Deepak Gupta
` (16 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
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>
---
disas/riscv.c | 18 +++++++++++++++++-
disas/riscv.h | 2 ++
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/disas/riscv.c b/disas/riscv.c
index c8364c2b07..c7c92acef7 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -974,6 +974,7 @@ typedef enum {
rv_op_amomaxu_h = 943,
rv_op_amocas_b = 944,
rv_op_amocas_h = 945,
+ rv_op_lpad = 946,
} rv_op;
/* register names */
@@ -2232,6 +2233,7 @@ const rv_opcode_data rvi_opcode_data[] = {
{ "amomaxu.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
{ "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
{ "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "lpad", rv_codec_lp, rv_fmt_imm, NULL, 0, 0, 0 },
};
/* CSR names */
@@ -2925,7 +2927,13 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 7: op = rv_op_andi; break;
}
break;
- case 5: op = rv_op_auipc; break;
+ case 5:
+ op = rv_op_auipc;
+ if (dec->cfg->ext_zicfilp &&
+ (((inst >> 7) & 0b11111) == 0b00000)) {
+ op = rv_op_lpad;
+ }
+ break;
case 6:
switch ((inst >> 12) & 0b111) {
case 0: op = rv_op_addiw; break;
@@ -4482,6 +4490,11 @@ static uint32_t operand_tbl_index(rv_inst inst)
return ((inst << 54) >> 56);
}
+static uint32_t operand_lpl(rv_inst inst)
+{
+ return inst >> 12;
+}
+
/* decode operands */
static void decode_inst_operands(rv_decode *dec, rv_isa isa)
@@ -4869,6 +4882,9 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa)
dec->imm = sextract32(operand_rs2(inst), 0, 5);
dec->imm1 = operand_imm2(inst);
break;
+ case rv_codec_lp:
+ dec->imm = operand_lpl(inst);
+ break;
};
}
diff --git a/disas/riscv.h b/disas/riscv.h
index 16a08e4895..1182457aff 100644
--- a/disas/riscv.h
+++ b/disas/riscv.h
@@ -166,6 +166,7 @@ typedef enum {
rv_codec_r2_immhl,
rv_codec_r2_imm2_imm5,
rv_codec_fli,
+ rv_codec_lp,
} rv_codec;
/* structures */
@@ -228,6 +229,7 @@ enum {
#define rv_fmt_rs1_rs2 "O\t1,2"
#define rv_fmt_rd_imm "O\t0,i"
#define rv_fmt_rd_uimm "O\t0,Ui"
+#define rv_fmt_imm "O\ti"
#define rv_fmt_rd_offset "O\t0,o"
#define rv_fmt_rd_uoffset "O\t0,Uo"
#define rv_fmt_rd_rs1_rs2 "O\t0,1,2"
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 08/24] linux-user/syscall: introduce prctl for indirect branch tracking
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (6 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 07/24] disas/riscv: enabled `lpad` disassembly Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-30 6:21 ` Richard Henderson
2024-07-29 17:53 ` [PATCH v2 09/24] linux-user/riscv: implement indirect branch tracking prctls Deepak Gupta
` (15 subsequent siblings)
23 siblings, 1 reply; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Each application enables indirect branch tracking (forward cfi) for itself
via prctl. Adding branch tracking prctl in linux-user/syscall.
Using same prctl code as proposed in cfi patches in kernel mailing list [1]
[1] - https://lore.kernel.org/all/20240403234054.2020347-1-debug@rivosinc.com/
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>
Co-developed-by: Jesse Huang <jesse.huang@sifive.com>
---
linux-user/syscall.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b8c278b91d..ec157c1088 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6295,6 +6295,17 @@ abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
# define PR_SME_VL_INHERIT (1 << 17)
#endif
+#ifndef PR_GET_INDIR_BR_LP_STATUS
+# define PR_GET_INDIR_BR_LP_STATUS 74
+#endif
+#ifndef PR_SET_INDIR_BR_LP_STATUS
+# define PR_SET_INDIR_BR_LP_STATUS 75
+# define PR_INDIR_BR_LP_ENABLE (1UL << 0)
+#endif
+#ifndef PR_LOCK_INDIR_BR_LP_STATUS
+# define PR_LOCK_INDIR_BR_LP_STATUS 76
+#endif
+
#include "target_prctl.h"
static abi_long do_prctl_inval0(CPUArchState *env)
@@ -6477,6 +6488,14 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2,
case PR_SET_TSC:
/* Disable to prevent the target disabling stuff we need. */
return -TARGET_EINVAL;
+ case PR_GET_INDIR_BR_LP_STATUS:
+ case PR_SET_INDIR_BR_LP_STATUS:
+ case PR_LOCK_INDIR_BR_LP_STATUS:
+#ifndef do_prctl_cfi
+ return do_prctl_inval1(env, arg2);
+#else
+ return do_prctl_cfi(env, option, arg2);
+#endif
default:
qemu_log_mask(LOG_UNIMP, "Unsupported prctl: " TARGET_ABI_FMT_ld "\n",
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH v2 08/24] linux-user/syscall: introduce prctl for indirect branch tracking
2024-07-29 17:53 ` [PATCH v2 08/24] linux-user/syscall: introduce prctl for indirect branch tracking Deepak Gupta
@ 2024-07-30 6:21 ` Richard Henderson
0 siblings, 0 replies; 35+ messages in thread
From: Richard Henderson @ 2024-07-30 6:21 UTC (permalink / raw)
To: qemu-devel
On 7/30/24 03:53, Deepak Gupta wrote:
> Each application enables indirect branch tracking (forward cfi) for itself
> via prctl. Adding branch tracking prctl in linux-user/syscall.
>
> Using same prctl code as proposed in cfi patches in kernel mailing list [1]
>
> [1] - https://lore.kernel.org/all/20240403234054.2020347-1-debug@rivosinc.com/
>
> 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>
> Co-developed-by: Jesse Huang <jesse.huang@sifive.com>
> ---
> linux-user/syscall.c | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index b8c278b91d..ec157c1088 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -6295,6 +6295,17 @@ abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
> # define PR_SME_VL_INHERIT (1 << 17)
> #endif
>
> +#ifndef PR_GET_INDIR_BR_LP_STATUS
> +# define PR_GET_INDIR_BR_LP_STATUS 74
> +#endif
> +#ifndef PR_SET_INDIR_BR_LP_STATUS
> +# define PR_SET_INDIR_BR_LP_STATUS 75
> +# define PR_INDIR_BR_LP_ENABLE (1UL << 0)
> +#endif
> +#ifndef PR_LOCK_INDIR_BR_LP_STATUS
> +# define PR_LOCK_INDIR_BR_LP_STATUS 76
> +#endif
This will of course have to wait until the uapi lands upstream.
> @@ -6477,6 +6488,14 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2,
> case PR_SET_TSC:
> /* Disable to prevent the target disabling stuff we need. */
> return -TARGET_EINVAL;
> + case PR_GET_INDIR_BR_LP_STATUS:
> + case PR_SET_INDIR_BR_LP_STATUS:
> + case PR_LOCK_INDIR_BR_LP_STATUS:
> +#ifndef do_prctl_cfi
> + return do_prctl_inval1(env, arg2);
> +#else
> + return do_prctl_cfi(env, option, arg2);
> +#endif
Do not combine 3 prctl into one.
Do not put the ifdef here; put it above with the rest, e.g.
#ifndef do_prctl_set_fp_mode
#define do_prctl_set_fp_mode do_prctl_inval1
#endif
r~
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v2 09/24] linux-user/riscv: implement indirect branch tracking prctls
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (7 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 08/24] linux-user/syscall: introduce prctl for indirect branch tracking Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-30 6:26 ` Richard Henderson
2024-07-29 17:53 ` [PATCH v2 10/24] target/riscv: Add zicfiss extension Deepak Gupta
` (14 subsequent siblings)
23 siblings, 1 reply; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Implements indirect branch tracking prctls for riscv. Setting and clearing
branch tracking prctl simply turns on/off `ufcfien` field in `env`.
tb flush is needed because branch tracking itself leverages tb creation
logic.
locking branch tracking (forward cfi) is not implemented yet (no need yet)
but added for completeness (kernel patches have this prctl)
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
Co-developed-by: Jesse Huang <jesse.huang@sifive.com>
Co-developed-by: Jim Shu <jim.shu@sifive.com>
Co-developed-by: Andy Chiu <andy.chiu@sifive.com>
---
linux-user/riscv/target_prctl.h | 43 +++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/linux-user/riscv/target_prctl.h b/linux-user/riscv/target_prctl.h
index eb53b31ad5..d7f9f954c9 100644
--- a/linux-user/riscv/target_prctl.h
+++ b/linux-user/riscv/target_prctl.h
@@ -1 +1,44 @@
/* No special prctl support required. */
+#ifndef RISCV_TARGET_PRCTL_H
+#define RISCV_TARGET_PRCTL_H
+
+/*
+ * -TARGET_EINVAL: Unsupported/Invalid flag for this architecture
+ * -TARGET_EACCES: try to set an already set CFI feature
+ * -TARGET_ENOENT: CFI feature is not supported by CPU
+ */
+static abi_long do_prctl_cfi(CPUArchState *env,
+ abi_long option, abi_long flag)
+{
+ if (env_archcpu(env)->cfg.ext_zicfilp) {
+
+ switch (option) {
+ case PR_GET_INDIR_BR_LP_STATUS:
+ abi_ulong fcfi_status = 0;
+ /* indirect branch tracking is enabled on the task or not */
+ fcfi_status |= (env->ufcfien ? PR_INDIR_BR_LP_ENABLE : 0);
+ return copy_to_user(flag, &fcfi_status, sizeof(fcfi_status)) ? \
+ -EFAULT : 0;
+
+ case PR_SET_INDIR_BR_LP_STATUS:
+ /* if any other bit is set, its invalid param */
+ if (flag & ~PR_INDIR_BR_LP_ENABLE) {
+ return -TARGET_EINVAL;
+ }
+ /* set or clear branch tracking */
+ env->ufcfien = (flag & PR_INDIR_BR_LP_ENABLE);
+ tb_flush(env_cpu(env));
+ return 0;
+
+ /* locking not implemented (also not needed for qemu-user) yet */
+ case PR_LOCK_INDIR_BR_LP_STATUS:
+ return -TARGET_EINVAL;
+ }
+ }
+
+ return -TARGET_ENOENT;
+}
+
+#define do_prctl_cfi do_prctl_cfi
+
+#endif
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 10/24] target/riscv: Add zicfiss extension
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (8 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 09/24] linux-user/riscv: implement indirect branch tracking prctls Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 11/24] target/riscv: introduce ssp and enabling controls for zicfiss Deepak Gupta
` (13 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
zicfiss [1] riscv cpu extension enables backward control flow integrity.
This patch sets up space for zicfiss extension in cpuconfig. And imple-
ments dependency on zicsr, zimop and zcmop extensions.
[1] - https://github.com/riscv/riscv-cfi
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>
---
target/riscv/cpu.c | 2 ++
target/riscv/cpu_cfg.h | 1 +
target/riscv/tcg/tcg-cpu.c | 15 +++++++++++++++
3 files changed, 18 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e1526c7ab5..54fcf380ff 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -107,6 +107,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zicclsm, PRIV_VERSION_1_11_0, has_priv_1_11),
ISA_EXT_DATA_ENTRY(ziccrse, PRIV_VERSION_1_11_0, has_priv_1_11),
ISA_EXT_DATA_ENTRY(zicfilp, PRIV_VERSION_1_12_0, ext_zicfilp),
+ ISA_EXT_DATA_ENTRY(zicfiss, PRIV_VERSION_1_13_0, ext_zicfiss),
ISA_EXT_DATA_ENTRY(zicond, PRIV_VERSION_1_12_0, ext_zicond),
ISA_EXT_DATA_ENTRY(zicntr, PRIV_VERSION_1_12_0, ext_zicntr),
ISA_EXT_DATA_ENTRY(zicsr, PRIV_VERSION_1_10_0, ext_zicsr),
@@ -1482,6 +1483,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false),
MULTI_EXT_CFG_BOOL("zifencei", ext_zifencei, true),
MULTI_EXT_CFG_BOOL("zicfilp", ext_zicfilp, false),
+ MULTI_EXT_CFG_BOOL("zicfiss", ext_zicfiss, false),
MULTI_EXT_CFG_BOOL("zicsr", ext_zicsr, true),
MULTI_EXT_CFG_BOOL("zihintntl", ext_zihintntl, true),
MULTI_EXT_CFG_BOOL("zihintpause", ext_zihintpause, true),
diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h
index 88d5defbb5..2499f38407 100644
--- a/target/riscv/cpu_cfg.h
+++ b/target/riscv/cpu_cfg.h
@@ -68,6 +68,7 @@ struct RISCVCPUConfig {
bool ext_zicbop;
bool ext_zicboz;
bool ext_zicfilp;
+ bool ext_zicfiss;
bool ext_zicond;
bool ext_zihintntl;
bool ext_zihintpause;
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index ed19586c9d..4fd2fd7a28 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -618,6 +618,21 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
cpu->cfg.ext_zihpm = false;
}
+ if (cpu->cfg.ext_zicfiss) {
+ if (!cpu->cfg.ext_zicsr) {
+ error_setg(errp, "zicfiss extension requires zicsr extension");
+ return;
+ }
+ if (!cpu->cfg.ext_zimop) {
+ error_setg(errp, "zicfiss extension requires zimop extension");
+ return;
+ }
+ if (cpu->cfg.ext_zca && !cpu->cfg.ext_zcmop) {
+ error_setg(errp, "zicfiss with zca requires zcmop extension");
+ return;
+ }
+ }
+
if (!cpu->cfg.ext_zihpm) {
cpu->cfg.pmu_mask = 0;
cpu->pmu_avail_ctrs = 0;
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 11/24] target/riscv: introduce ssp and enabling controls for zicfiss
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (9 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 10/24] target/riscv: Add zicfiss extension Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 12/24] target/riscv: tb flag for shadow stack instructions Deepak Gupta
` (12 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
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.
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>
---
target/riscv/cpu.c | 3 ++
target/riscv/cpu.h | 2 ++
target/riscv/cpu_bits.h | 6 ++++
target/riscv/csr.c | 74 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 85 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 54fcf380ff..6b50ae0e45 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -998,6 +998,9 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
/* on reset elp is set to NO_LP_EXPECTED */
env->elp = NO_LP_EXPECTED;
+ /* on reset ssp is set to 0 */
+ env->ssp = 0;
+
/*
* 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 7fed5d2750..81283a1d76 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -224,6 +224,8 @@ struct CPUArchState {
/* elp state for zicfilp extension */
cfi_elp elp;
+ /* shadow stack register for zicfiss extension */
+ target_ulong ssp;
/* sw check code for sw check exception */
target_ulong sw_check_code;
#ifdef CONFIG_USER_ONLY
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 477e24feaf..589326e516 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -34,6 +34,9 @@
/* Control and Status Registers */
+/* zicfiss user ssp csr */
+#define CSR_SSP 0x011
+
/* User Trap Setup */
#define CSR_USTATUS 0x000
#define CSR_UIE 0x004
@@ -760,6 +763,7 @@ typedef enum RISCVException {
/* Execution environment configuration bits */
#define MENVCFG_FIOM BIT(0)
#define MENVCFG_LPE BIT(2) /* zicfilp */
+#define MENVCFG_SSE BIT(3) /* zicfiss */
#define MENVCFG_CBIE (3UL << 4)
#define MENVCFG_CBCFE BIT(6)
#define MENVCFG_CBZE BIT(7)
@@ -774,12 +778,14 @@ typedef enum RISCVException {
#define SENVCFG_FIOM MENVCFG_FIOM
#define SENVCFG_LPE MENVCFG_LPE
+#define SENVCFG_SSE MENVCFG_SSE
#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_SSE MENVCFG_SSE
#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 a5a969a377..d72d6289fb 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -185,6 +185,47 @@ static RISCVException zcmt(CPURISCVState *env, int csrno)
return RISCV_EXCP_NONE;
}
+static RISCVException cfi_ss(CPURISCVState *env, int csrno)
+{
+ /* no cfi extension, access to csr is illegal */
+ if (!env_archcpu(env)->cfg.ext_zicfiss) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ /*
+ * CONFIG_USER_MODE always allow access for now. Better for user mode only
+ * functionality
+ */
+#if !defined(CONFIG_USER_ONLY)
+ if (env->debugger) {
+ return RISCV_EXCP_NONE;
+ }
+ /* current priv not M */
+ if (env->priv != PRV_M) {
+ /* menvcfg says no shadow stack enable */
+ if (!get_field(env->menvcfg, MENVCFG_SSE)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ /* V = 1 and henvcfg says no shadow stack enable */
+ if (env->virt_enabled &&
+ !get_field(env->henvcfg, HENVCFG_SSE)) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+
+ /*
+ * SSP are not accessible to U mode if disabled via senvcfg
+ * CSR
+ */
+ if ((env->priv == PRV_U) &&
+ (!get_field(env->senvcfg, SENVCFG_SSE))) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ }
+#endif
+
+ return RISCV_EXCP_NONE;
+}
+
#if !defined(CONFIG_USER_ONLY)
static RISCVException mctr(CPURISCVState *env, int csrno)
{
@@ -596,6 +637,19 @@ static RISCVException seed(CPURISCVState *env, int csrno)
#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 */
static RISCVException read_fflags(CPURISCVState *env, int csrno,
target_ulong *val)
@@ -2111,6 +2165,10 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= MENVCFG_LPE;
}
+
+ if (env_archcpu(env)->cfg.ext_zicfiss) {
+ mask |= MENVCFG_SSE;
+ }
}
env->menvcfg = (env->menvcfg & ~mask) | (val & mask);
@@ -2167,6 +2225,13 @@ static RISCVException write_senvcfg(CPURISCVState *env, int csrno,
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);
return RISCV_EXCP_NONE;
}
@@ -2208,6 +2273,12 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
if (env_archcpu(env)->cfg.ext_zicfilp) {
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);
@@ -4663,6 +4734,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
/* Zcmt Extension */
[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)
/* Machine Timers and Counters */
[CSR_MCYCLE] = { "mcycle", any, read_hpmcounter,
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 12/24] target/riscv: tb flag for shadow stack instructions
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (10 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 11/24] target/riscv: introduce ssp and enabling controls for zicfiss Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 13/24] target/riscv: implement zicfiss instructions Deepak Gupta
` (11 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Shadow stack instructions can be decoded as zimop / zcmop or shadow stack
instructions depending on whether shadow stack are enabled at current
privilege. This requires a TB flag so that correct TB generation and correct
TB lookup happens. `DisasContext` gets a field indicating whether bcfi is
enabled or not.
This patch also implements helper bcfi function which determines if bcfi
is enabled at current privilege or not. qemu-user also gets field
`ubcfien` indicating whether qemu user has shadow stack enabled or not.
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>
---
target/riscv/cpu.c | 2 ++
target/riscv/cpu.h | 4 ++++
target/riscv/cpu_helper.c | 30 ++++++++++++++++++++++++++++++
target/riscv/translate.c | 4 ++++
4 files changed, 40 insertions(+)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 6b50ae0e45..e1ff246c24 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1029,6 +1029,8 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
#ifdef CONFIG_USER_ONLY
/* qemu-user for riscv, fcfi is off by default */
env->ufcfien = false;
+ /* qemu-user for riscv, bcfi is off by default */
+ env->ubcfien = false;
#endif
#ifndef CONFIG_USER_ONLY
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 81283a1d76..0e0a9d2be1 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -231,6 +231,7 @@ struct CPUArchState {
#ifdef CONFIG_USER_ONLY
uint32_t elf_flags;
bool ufcfien;
+ bool ubcfien;
#endif
#ifndef CONFIG_USER_ONLY
@@ -536,6 +537,7 @@ bool riscv_cpu_vector_enabled(CPURISCVState *env);
void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
int riscv_env_mmu_index(CPURISCVState *env, bool ifetch);
bool cpu_get_fcfien(CPURISCVState *env);
+bool cpu_get_bcfien(CPURISCVState *env);
G_NORETURN void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr);
@@ -610,6 +612,8 @@ FIELD(TB_FLAGS, PRIV, 24, 2)
FIELD(TB_FLAGS, AXL, 26, 2)
/* zicfilp needs a TB flag to track indirect branches */
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)
#ifdef TARGET_RISCV32
#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 2cb1d45467..ce68f5af72 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -93,6 +93,32 @@ bool cpu_get_fcfien(CPURISCVState *env)
#endif
}
+bool cpu_get_bcfien(CPURISCVState *env)
+{
+#ifdef CONFIG_USER_ONLY
+ return env->ubcfien;
+#else
+ /* no cfi extension, return false */
+ if (!env_archcpu(env)->cfg.ext_zicfiss) {
+ return false;
+ }
+
+ switch (env->priv) {
+ case PRV_U:
+ return (env->senvcfg & SENVCFG_SSE) ? true : false;
+ case PRV_S:
+ if (env->virt_enabled) {
+ return (env->henvcfg & HENVCFG_SSE) ? true : false;
+ }
+ return (env->menvcfg & MENVCFG_SSE) ? true : false;
+ case PRV_M: /* M-mode shadow stack is always on if hart implements */
+ return true;
+ default:
+ g_assert_not_reached();
+ }
+#endif
+}
+
void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
uint64_t *cs_base, uint32_t *pflags)
{
@@ -146,6 +172,10 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc,
env->elp != NO_LP_EXPECTED);
}
+ if (cpu_get_bcfien(env)) {
+ flags = FIELD_DP32(flags, TB_FLAGS, BCFI_ENABLED, 1);
+ }
+
#ifdef CONFIG_USER_ONLY
fs = EXT_STATUS_DIRTY;
vs = EXT_STATUS_DIRTY;
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index c746d7df08..34c9bf093d 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -121,6 +121,8 @@ typedef struct DisasContext {
/* zicfilp extension. cfi enabled or not. lp expected or not */
bool fcfi_enabled;
bool fcfi_lp_expected;
+ /* zicfiss extension, if shadow stack was enabled during TB gen */
+ bool bcfi_enabled;
} DisasContext;
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -1243,6 +1245,8 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->pm_base_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_BASE_ENABLED);
ctx->ztso = cpu->cfg.ext_ztso;
ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER);
+ ctx->bcfi_enabled = cpu_get_bcfien(env) &&
+ FIELD_EX32(tb_flags, TB_FLAGS, BCFI_ENABLED);
ctx->fcfi_lp_expected = FIELD_EX32(tb_flags, TB_FLAGS, FCFI_LP_EXPECTED);
ctx->fcfi_enabled = cpu_get_fcfien(env) && ctx->fcfi_lp_expected;
ctx->zero = tcg_constant_tl(0);
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 13/24] target/riscv: implement zicfiss instructions
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (11 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 12/24] target/riscv: tb flag for shadow stack instructions Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 14/24] target/riscv: compressed encodings for sspush and sspopchk Deepak Gupta
` (10 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
zicfiss has following instructions
- sspopchk: pops a value from shadow stack and compares with x1/x5.
If they dont match, reports a sw check exception with tval = 3.
- sspush: pushes value in x1/x5 on shadow stack
- ssrdp: reads current shadow stack
- ssamoswap: swaps contents of shadow stack atomically
sspopchk/sspush/ssrdp default to zimop if zimop implemented and SSE=0
If SSE=0, ssamoswap is illegal instruction exception.
This patch implements shadow stack operations for qemu-user and shadow
stack is not protected.
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>
---
target/riscv/cpu_bits.h | 2 +
target/riscv/helper.h | 2 +
target/riscv/insn32.decode | 17 +-
target/riscv/insn_trans/trans_rva.c.inc | 47 ++++++
target/riscv/insn_trans/trans_rvzicfiss.c.inc | 149 ++++++++++++++++++
target/riscv/op_helper.c | 9 ++
target/riscv/translate.c | 1 +
7 files changed, 225 insertions(+), 2 deletions(-)
create mode 100644 target/riscv/insn_trans/trans_rvzicfiss.c.inc
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 589326e516..8e179d6965 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -696,6 +696,8 @@ typedef enum RISCVException {
/* zicfilp defines lp violation results in sw check with tval = 2*/
#define RISCV_EXCP_SW_CHECK_FCFI_TVAL 2
+/* zicfiss defines ss violation results in sw check with tval = 3*/
+#define RISCV_EXCP_SW_CHECK_BCFI_TVAL 3
#define RISCV_EXCP_INT_FLAG 0x80000000
#define RISCV_EXCP_INT_MASK 0x7fffffff
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index ab55bbbf73..4efb7ba4df 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -124,6 +124,8 @@ DEF_HELPER_2(cbo_zero, void, env, tl)
/* Forward CFI label checking */
DEF_HELPER_2(cfi_jalr, void, env, int)
DEF_HELPER_2(cfi_check_landing_pad, void, env, int)
+/* helper for sschk mismatch (zicfiss) */
+DEF_HELPER_3(sschk_mismatch, void, env, tl, tl)
/* Special functions */
DEF_HELPER_2(csrr, tl, env, int)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index c963c59c8e..c59c992ce2 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -65,8 +65,10 @@
# Formats 32:
@r ....... ..... ..... ... ..... ....... &r %rs2 %rs1 %rd
@i ............ ..... ... ..... ....... &i imm=%imm_i %rs1 %rd
+@ss_pop ............ ..... ... ..... ....... &i imm=0 %rs1 rd=0
@b ....... ..... ..... ... ..... ....... &b imm=%imm_b %rs2 %rs1
@s ....... ..... ..... ... ..... ....... &s imm=%imm_s %rs2 %rs1
+@ss_push ....... ..... ..... ... ..... ....... &s imm=0 %rs2 rs1=0
@u .................... ..... ....... &u imm=%imm_u %rd
@j .................... ..... ....... &j imm=%imm_j %rd
@@ -247,6 +249,7 @@ remud 0000001 ..... ..... 111 ..... 1111011 @r
lr_w 00010 . . 00000 ..... 010 ..... 0101111 @atom_ld
sc_w 00011 . . ..... ..... 010 ..... 0101111 @atom_st
amoswap_w 00001 . . ..... ..... 010 ..... 0101111 @atom_st
+ssamoswap_w 01001 . . ..... ..... 010 ..... 0101111 @atom_st
amoadd_w 00000 . . ..... ..... 010 ..... 0101111 @atom_st
amoxor_w 00100 . . ..... ..... 010 ..... 0101111 @atom_st
amoand_w 01100 . . ..... ..... 010 ..... 0101111 @atom_st
@@ -260,6 +263,7 @@ amomaxu_w 11100 . . ..... ..... 010 ..... 0101111 @atom_st
lr_d 00010 . . 00000 ..... 011 ..... 0101111 @atom_ld
sc_d 00011 . . ..... ..... 011 ..... 0101111 @atom_st
amoswap_d 00001 . . ..... ..... 011 ..... 0101111 @atom_st
+ssamoswap_d 01001 . . ..... ..... 011 ..... 0101111 @atom_st
amoadd_d 00000 . . ..... ..... 011 ..... 0101111 @atom_st
amoxor_d 00100 . . ..... ..... 011 ..... 0101111 @atom_st
amoand_d 01100 . . ..... ..... 011 ..... 0101111 @atom_st
@@ -1023,8 +1027,17 @@ amocas_d 00101 . . ..... ..... 011 ..... 0101111 @atom_st
amocas_q 00101 . . ..... ..... 100 ..... 0101111 @atom_st
# *** Zimop may-be-operation extension ***
-mop_r_n 1 . 00 .. 0111 .. ..... 100 ..... 1110011 @mop5
-mop_rr_n 1 . 00 .. 1 ..... ..... 100 ..... 1110011 @mop3
+{
+ # zicfiss instructions carved out of mop.r
+ ssrdp 1100110 11100 00000 100 ..... 1110011 %rd
+ sspopchk 1100110 11100 ..... 100 00000 1110011 @ss_pop
+ mop_r_n 1 . 00 .. 0111 .. ..... 100 ..... 1110011 @mop5
+}
+{
+ # zicfiss instruction carved out of mop.rr
+ sspush 1100111 ..... 00000 100 00000 1110011 @ss_push
+ mop_rr_n 1 . 00 .. 1 ..... ..... 100 ..... 1110011 @mop3
+}
# *** Zabhb Standard Extension ***
amoswap_b 00001 . . ..... ..... 000 ..... 0101111 @atom_st
diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc
index 39bbf60f3c..db6c03f6a8 100644
--- a/target/riscv/insn_trans/trans_rva.c.inc
+++ b/target/riscv/insn_trans/trans_rva.c.inc
@@ -18,6 +18,8 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "exec/memop.h"
+
#define REQUIRE_A_OR_ZAAMO(ctx) do { \
if (!ctx->cfg_ptr->ext_zaamo && !has_ext(ctx, RVA)) { \
return false; \
@@ -114,6 +116,28 @@ static bool trans_amoswap_w(DisasContext *ctx, arg_amoswap_w *a)
return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_TESL);
}
+static bool trans_ssamoswap_w(DisasContext *ctx, arg_amoswap_w *a)
+{
+ REQUIRE_A_OR_ZAAMO(ctx);
+ /* default for qemu-user, use regular RW memory and thus mmu_idx=0 */
+ int ss_mmu_idx = 0;
+
+ /* back cfi was not enabled, return false */
+ if (!ctx->bcfi_enabled) {
+ return false;
+ }
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+
+ decode_save_opc(ctx);
+ src1 = get_address(ctx, a->rs1, 0);
+
+ tcg_gen_atomic_xchg_tl(dest, src1, src2, ss_mmu_idx, (MO_ALIGN | MO_TESL));
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
static bool trans_amoadd_w(DisasContext *ctx, arg_amoadd_w *a)
{
REQUIRE_A_OR_ZAAMO(ctx);
@@ -183,6 +207,29 @@ static bool trans_amoswap_d(DisasContext *ctx, arg_amoswap_d *a)
return gen_amo(ctx, a, &tcg_gen_atomic_xchg_tl, MO_TEUQ);
}
+static bool trans_ssamoswap_d(DisasContext *ctx, arg_amoswap_w *a)
+{
+ REQUIRE_64BIT(ctx);
+ REQUIRE_A_OR_ZAAMO(ctx);
+ /* default for qemu-user, use regular RW memory and thus mmu_idx=0 */
+ int ss_mmu_idx = 0;
+
+ /* back cfi was not enabled, return false */
+ if (!ctx->bcfi_enabled) {
+ return false;
+ }
+
+ TCGv dest = dest_gpr(ctx, a->rd);
+ TCGv src1, src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+
+ decode_save_opc(ctx);
+ src1 = get_address(ctx, a->rs1, 0);
+
+ tcg_gen_atomic_xchg_tl(dest, src1, src2, ss_mmu_idx, (MO_ALIGN | MO_TESQ));
+ gen_set_gpr(ctx, a->rd, dest);
+ return true;
+}
+
static bool trans_amoadd_d(DisasContext *ctx, arg_amoadd_d *a)
{
REQUIRE_64BIT(ctx);
diff --git a/target/riscv/insn_trans/trans_rvzicfiss.c.inc b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
new file mode 100644
index 0000000000..bac65d4166
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
@@ -0,0 +1,149 @@
+/*
+ * RISC-V translation routines for the Control-Flow Integrity Extension
+ *
+ * Copyright (c) 2024 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static MemOp mxl_memop(DisasContext *ctx)
+{
+ switch (get_xl(ctx)) {
+ case MXL_RV32:
+ return MO_TEUL;
+
+ case MXL_RV64:
+ return MO_TEUQ;
+
+ case MXL_RV128:
+ return MO_TEUO;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a)
+{
+ /* default for qemu-user, use regular RW memory and thus mmu_idx=0 */
+ int ss_mmu_idx = 0;
+
+ /* sspopchk only supported on 32bit and 64bit */
+ if (get_xl(ctx) != MXL_RV32 && get_xl(ctx) != MXL_RV64) {
+ return false;
+ }
+
+ /* back cfi was not enabled, return false */
+ if (!ctx->bcfi_enabled) {
+ return false;
+ }
+
+ /*
+ * sspopchk can only compare with x1 or x5. Everything else defaults to
+ * zimops
+ */
+
+ if (a->rs1 != 1 && a->rs1 != 5) {
+ return false;
+ }
+
+ /*
+ * get data in TCGv using get_gpr
+ * get addr in TCGv using gen_helper_csrr on CSR_SSP
+ * use some tcg subtract arithmetic (subtract by XLEN) on addr
+ * perform ss store on computed address
+ */
+
+ TCGv addr = tcg_temp_new();
+ uint32_t tmp = (get_xl(ctx) == MXL_RV64) ? 8 : 4;
+ TCGv_i32 ssp_csr = tcg_constant_i32(CSR_SSP);
+ TCGv data = tcg_temp_new();
+ gen_helper_csrr(addr, tcg_env, ssp_csr);
+
+ tcg_gen_qemu_ld_tl(data, addr, ss_mmu_idx,
+ mxl_memop(ctx) | MO_ALIGN);
+ TCGv rs1 = get_gpr(ctx, a->rs1, EXT_NONE);
+ /*
+ * add XLEN/bitwidth to addr, align to XLEN . How do i do that? Is below
+ * the right way
+ */
+ tcg_gen_addi_tl(addr, addr, tmp);
+ gen_helper_sschk_mismatch(tcg_env, rs1, data);
+ gen_helper_csrw(tcg_env, ssp_csr, addr);
+
+ return true;
+}
+
+static bool trans_sspush(DisasContext *ctx, arg_sspush *a)
+{
+ /* default for qemu-user, use regular RW memory and thus mmu_idx=0 */
+ int ss_mmu_idx = 0;
+
+ /* sspush only supported on 32bit and 64bit */
+ if (get_xl(ctx) != MXL_RV32 && get_xl(ctx) != MXL_RV64) {
+ return false;
+ }
+
+ /* back cfi was not enabled, return false */
+ if (!ctx->bcfi_enabled) {
+ return false;
+ }
+
+ /*
+ * sspush can only push from x1 or x5. Everything else defaults to zimop
+ */
+ if (a->rs2 != 1 && a->rs2 != 5) {
+ return false;
+ }
+
+ /*
+ * get data in TCGv using get_gpr
+ * get addr in TCGv using gen_helper_csrr on CSR_SSP
+ * use some tcg subtract arithmetic (subtract by XLEN) on addr
+ * perform ss store on computed address
+ */
+
+ TCGv addr = tcg_temp_new();
+ int tmp = (get_xl(ctx) == MXL_RV64) ? -8 : -4;
+ TCGv_i32 ssp_csr = tcg_constant_i32(CSR_SSP);
+ TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
+ gen_helper_csrr(addr, tcg_env, ssp_csr);
+
+ tcg_gen_addi_tl(addr, addr, tmp);
+
+ tcg_gen_qemu_st_tl(data, addr, ss_mmu_idx,
+ mxl_memop(ctx) | MO_ALIGN);
+ gen_helper_csrw(tcg_env, ssp_csr, addr);
+
+ return true;
+}
+
+static bool trans_ssrdp(DisasContext *ctx, arg_ssrdp *a)
+{
+ /* ssrdp only supported on 32bit and 64bit */
+ if (get_xl(ctx) != MXL_RV32 && get_xl(ctx) != MXL_RV64) {
+ return false;
+ }
+
+ /* back cfi was not enabled, return false */
+ if (!ctx->bcfi_enabled) {
+ return false;
+ }
+
+ TCGv dest = get_gpr(ctx, a->rd, EXT_NONE);
+ TCGv_i32 ssp_csr = tcg_constant_i32(CSR_SSP);
+ gen_helper_csrr(dest, tcg_env, ssp_csr);
+ gen_set_gpr(ctx, a->rd, dest);
+
+ return true;
+}
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 2d152f0a00..54baa3a966 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -291,6 +291,15 @@ void helper_cfi_check_landing_pad(CPURISCVState *env, int lbl)
}
}
+void helper_sschk_mismatch(CPURISCVState *env, target_ulong rs1,
+ target_ulong ssra)
+{
+ if (rs1 != ssra) {
+ env->sw_check_code = RISCV_EXCP_SW_CHECK_BCFI_TVAL;
+ riscv_raise_exception(env, RISCV_EXCP_SW_CHECK, GETPC());
+ }
+}
+
#ifndef CONFIG_USER_ONLY
target_ulong helper_sret(CPURISCVState *env)
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 34c9bf093d..9152a963ee 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1143,6 +1143,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
#include "insn_trans/trans_rvzawrs.c.inc"
#include "insn_trans/trans_rvzicbo.c.inc"
#include "insn_trans/trans_rvzimop.c.inc"
+#include "insn_trans/trans_rvzicfiss.c.inc"
#include "insn_trans/trans_rvzfa.c.inc"
#include "insn_trans/trans_rvzfh.c.inc"
#include "insn_trans/trans_rvk.c.inc"
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 14/24] target/riscv: compressed encodings for sspush and sspopchk
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (12 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 13/24] target/riscv: implement zicfiss instructions Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 15/24] target/riscv: mmu changes for zicfiss shadow stack protection Deepak Gupta
` (9 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
sspush/sspopchk have compressed encodings carved out of zcmops.
compressed sspush is designated as c.mop.1 while compressed sspopchk
is designated as c.mop.5.
Note that c.sspush x1 exists while c.sspush x5 doesn't. Similarly
c.sspopchk x5 exists while c.sspopchk x1 doesn't.
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>
---
target/riscv/insn16.decode | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/target/riscv/insn16.decode b/target/riscv/insn16.decode
index 3953bcf82d..d9fb74fef6 100644
--- a/target/riscv/insn16.decode
+++ b/target/riscv/insn16.decode
@@ -69,10 +69,12 @@
# Formats 16:
@cr .... ..... ..... .. &r rs2=%rs2_5 rs1=%rd %rd
@ci ... . ..... ..... .. &i imm=%imm_ci rs1=%rd %rd
+@c_sspop ... . ..... ..... .. &i imm=0 rs1=5 rd=0
@cl_q ... . ..... ..... .. &i imm=%uimm_cl_q rs1=%rs1_3 rd=%rs2_3
@cl_d ... ... ... .. ... .. &i imm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
@cl_w ... ... ... .. ... .. &i imm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
@cs_2 ... ... ... .. ... .. &r rs2=%rs2_3 rs1=%rs1_3 rd=%rs1_3
+@c_sspush ... ... ... .. ... .. &s imm=0 rs1=0 rs2=1
@cs_q ... ... ... .. ... .. &s imm=%uimm_cl_q rs1=%rs1_3 rs2=%rs2_3
@cs_d ... ... ... .. ... .. &s imm=%uimm_cl_d rs1=%rs1_3 rs2=%rs2_3
@cs_w ... ... ... .. ... .. &s imm=%uimm_cl_w rs1=%rs1_3 rs2=%rs2_3
@@ -140,6 +142,8 @@ sw 110 ... ... .. ... 00 @cs_w
addi 000 . ..... ..... 01 @ci
addi 010 . ..... ..... 01 @c_li
{
+ sspush 011 0 00001 00000 01 @c_sspush # c.sspush x1 carving out of zcmops
+ sspopchk 011 0 00101 00000 01 @c_sspop # c.sspopchk x5 carving out of zcmops
c_mop_n 011 0 0 n:3 1 00000 01
illegal 011 0 ----- 00000 01 # c.addi16sp and c.lui, RES nzimm=0
addi 011 . 00010 ..... 01 @c_addi16sp
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 15/24] target/riscv: mmu changes for zicfiss shadow stack protection
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (13 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 14/24] target/riscv: compressed encodings for sspush and sspopchk Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 16/24] target/riscv: shadow stack mmu index for shadow stack instructions Deepak Gupta
` (8 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
zicfiss protects shadow stack using new page table encodings PTE.W=0,
PTE.R=0 and PTE.X=0. This encoding is reserved if zicfiss is not
implemented or if shadow stack are not enabled.
Loads on shadow stack memory are allowed while stores to shadow stack
memory leads to access faults. Shadow stack accesses to RO memory
leads to store page fault.
To implement special nature of shadow stack memory where only selected
stores (shadow stack stores from sspush) have to be allowed while rest
of regular stores disallowed, new MMU TLB index is created for shadow
stack.
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
target/riscv/cpu_helper.c | 61 +++++++++++++++++++++++++++++++++++++--
target/riscv/internals.h | 3 ++
2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index ce68f5af72..7942587a56 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -819,6 +819,18 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
env->load_res = -1;
}
+static bool legal_sstack_access(int access_type, bool sstack_inst,
+ bool sstack_attribute)
+{
+ /*
+ * Read/write/execution permissions are checked as usual. Shadow
+ * stack enforcement is just that (1) instruction type must match
+ * the attribute unless (2) a non-SS load to an SS region.
+ */
+ return (sstack_inst == sstack_attribute) ||
+ ((access_type == MMU_DATA_LOAD) && sstack_attribute);
+}
+
/*
* get_physical_address_pmp - check PMP permission for this physical address
*
@@ -896,6 +908,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
hwaddr ppn;
int napot_bits = 0;
target_ulong napot_mask;
+ bool is_sstack_insn = ((mmu_idx & MMU_IDX_SS_ACCESS) == MMU_IDX_SS_ACCESS);
+ bool sstack_page = false;
/*
* Check if we should use the background registers for the two
@@ -1104,15 +1118,45 @@ restart:
return TRANSLATE_FAIL;
}
+ /*
+ * When backward CFI is enabled, the R=0, W=1, X=0 reserved encoding
+ * is used to mark Shadow Stack (SS) pages. If back CFI enabled, allow
+ * normal loads on SS pages, regular stores raise store access fault
+ * and avoid hitting the reserved-encoding case. Only shadow stack
+ * stores are allowed on SS pages. Shadow stack loads and stores on
+ * regular memory (non-SS) raise load and store/AMO access fault.
+ * Second stage translations don't participate in Shadow Stack.
+ */
+ sstack_page = (cpu_get_bcfien(env) && first_stage &&
+ ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W));
+
/* Check for reserved combinations of RWX flags. */
switch (pte & (PTE_R | PTE_W | PTE_X)) {
- case PTE_W:
case PTE_W | PTE_X:
+ case PTE_W:
+ if (sstack_page) { /* if shadow stack page, PTE_W is not reserved */
+ break;
+ }
return TRANSLATE_FAIL;
}
+ /* Illegal combo of instruction type and page attribute */
+ if (!legal_sstack_access(access_type, is_sstack_insn,
+ sstack_page)) {
+ /* shadow stack instruction and RO page then it's a page fault */
+ if (is_sstack_insn && ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_R)) {
+ return TRANSLATE_FAIL;
+ }
+ /* In all other cases it's an access fault, so raise PMP_FAIL */
+ return TRANSLATE_PMP_FAIL;
+ }
+
int prot = 0;
- if (pte & PTE_R) {
+ /*
+ * If PTE has read bit in it or it's shadow stack page,
+ * then reads allowed
+ */
+ if ((pte & PTE_R) || sstack_page) {
prot |= PAGE_READ;
}
if (pte & PTE_W) {
@@ -1350,9 +1394,17 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
break;
case MMU_DATA_LOAD:
cs->exception_index = RISCV_EXCP_LOAD_ADDR_MIS;
+ /* shadow stack mis aligned accesses are access faults */
+ if (mmu_idx & MMU_IDX_SS_ACCESS) {
+ cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT;
+ }
break;
case MMU_DATA_STORE:
cs->exception_index = RISCV_EXCP_STORE_AMO_ADDR_MIS;
+ /* shadow stack mis aligned accesses are access faults */
+ if (mmu_idx & MMU_IDX_SS_ACCESS) {
+ cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
+ }
break;
default:
g_assert_not_reached();
@@ -1408,6 +1460,11 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
__func__, address, access_type, mmu_idx);
+ /* If shadow stack instruction initiated this access, treat it as store */
+ if (mmu_idx & MMU_IDX_SS_ACCESS) {
+ access_type = MMU_DATA_STORE;
+ }
+
pmu_tlb_fill_incr_ctr(cpu, access_type);
if (two_stage_lookup) {
/* Two stage lookup */
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
index 0ac17bc5ad..dad0657c80 100644
--- a/target/riscv/internals.h
+++ b/target/riscv/internals.h
@@ -30,12 +30,15 @@
* - U+2STAGE 0b100
* - S+2STAGE 0b101
* - S+SUM+2STAGE 0b110
+ * - Shadow stack+U 0b1000
+ * - Shadow stack+S 0b1001
*/
#define MMUIdx_U 0
#define MMUIdx_S 1
#define MMUIdx_S_SUM 2
#define MMUIdx_M 3
#define MMU_2STAGE_BIT (1 << 2)
+#define MMU_IDX_SS_ACCESS (1 << 3)
static inline int mmuidx_priv(int mmu_idx)
{
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 16/24] target/riscv: shadow stack mmu index for shadow stack instructions
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (14 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 15/24] target/riscv: mmu changes for zicfiss shadow stack protection Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 17/24] linux-user/syscall: introduce prctl for shadow stack enable/disable Deepak Gupta
` (7 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
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/insn_trans/trans_rvzicfiss.c.inc | 6 +++++
target/riscv/internals.h | 1 +
target/riscv/translate.c | 25 +++++++++++++++++++
6 files changed, 56 insertions(+)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0e0a9d2be1..82475490ab 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -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)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 7942587a56..b2bb1e4293 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -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);
diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc
index db6c03f6a8..68b71339a3 100644
--- a/target/riscv/insn_trans/trans_rva.c.inc
+++ b/target/riscv/insn_trans/trans_rva.c.inc
@@ -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);
diff --git a/target/riscv/insn_trans/trans_rvzicfiss.c.inc b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
index bac65d4166..9c3c872f59 100644
--- a/target/riscv/insn_trans/trans_rvzicfiss.c.inc
+++ b/target/riscv/insn_trans/trans_rvzicfiss.c.inc
@@ -69,6 +69,9 @@ static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a)
TCGv_i32 ssp_csr = tcg_constant_i32(CSR_SSP);
TCGv data = tcg_temp_new();
gen_helper_csrr(addr, tcg_env, ssp_csr);
+#ifndef CONFIG_USER_ONLY
+ ss_mmu_idx = get_ss_index(ctx);
+#endif
tcg_gen_qemu_ld_tl(data, addr, ss_mmu_idx,
mxl_memop(ctx) | MO_ALIGN);
@@ -118,6 +121,9 @@ static bool trans_sspush(DisasContext *ctx, arg_sspush *a)
TCGv_i32 ssp_csr = tcg_constant_i32(CSR_SSP);
TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
gen_helper_csrr(addr, tcg_env, ssp_csr);
+#ifndef CONFIG_USER_ONLY
+ ss_mmu_idx = get_ss_index(ctx);
+#endif
tcg_gen_addi_tl(addr, addr, tmp);
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
index dad0657c80..5147d6bf90 100644
--- a/target/riscv/internals.h
+++ b/target/riscv/internals.h
@@ -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
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 9152a963ee..ad0f841807 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -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"
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 17/24] linux-user/syscall: introduce prctl for shadow stack enable/disable
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (15 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 16/24] target/riscv: shadow stack mmu index for shadow stack instructions Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 18/24] linux-user/riscv: setup/teardown zicfiss shadow stack for qemu-user Deepak Gupta
` (6 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Each application enables shadow stack for itself via prctl. Using prctl
codes as proposed in riscv cfi patches on kernel mailing list [1]
[1] - https://lore.kernel.org/all/20240403234054.2020347-1-debug@rivosinc.com/
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>
Co-developed-by: Jesse Huang <jesse.huang@sifive.com>
---
linux-user/syscall.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index ec157c1088..f879be7cfe 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -6295,6 +6295,18 @@ abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
# define PR_SME_VL_INHERIT (1 << 17)
#endif
+#ifndef PR_GET_SHADOW_STACK_STATUS
+# define PR_GET_SHADOW_STACK_STATUS 71
+#endif
+#ifndef PR_SET_SHADOW_STACK_STATUS
+# define PR_SET_SHADOW_STACK_STATUS 72
+# define PR_SHADOW_STACK_ENABLE (1UL << 0)
+# define PR_SHADOW_STACK_WRITE (1UL << 1)
+# define PR_SHADOW_STACK_PUSH (1UL << 2)
+#endif
+#ifndef PR_LOCK_SHADOW_STACK_STATUS
+# define PR_LOCK_SHADOW_STACK_STATUS 73
+#endif
#ifndef PR_GET_INDIR_BR_LP_STATUS
# define PR_GET_INDIR_BR_LP_STATUS 74
#endif
@@ -6488,6 +6500,9 @@ static abi_long do_prctl(CPUArchState *env, abi_long option, abi_long arg2,
case PR_SET_TSC:
/* Disable to prevent the target disabling stuff we need. */
return -TARGET_EINVAL;
+ case PR_GET_SHADOW_STACK_STATUS:
+ case PR_SET_SHADOW_STACK_STATUS:
+ case PR_LOCK_SHADOW_STACK_STATUS:
case PR_GET_INDIR_BR_LP_STATUS:
case PR_SET_INDIR_BR_LP_STATUS:
case PR_LOCK_INDIR_BR_LP_STATUS:
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 18/24] linux-user/riscv: setup/teardown zicfiss shadow stack for qemu-user
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (16 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 17/24] linux-user/syscall: introduce prctl for shadow stack enable/disable Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 19/24] disas/riscv: enable disassembly for zicfiss instructions Deepak Gupta
` (5 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Implements shadow stack related prctls for qemu-user on riscv. Allocates
shadow stack from host memory using `target_mmap` and tears down when
user issues prctl to disable using `target_munmap`.
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
Co-developed-by: Jesse Huang <jesse.huang@sifive.com>
Co-developed-by: Jim Shu <jim.shu@sifive.com>
Co-developed-by: Andy Chiu <andy.chiu@sifive.com>
---
linux-user/riscv/cpu_loop.c | 50 +++++++++++++++++++++++++++++++++
linux-user/riscv/target_cpu.h | 7 +++++
linux-user/riscv/target_prctl.h | 27 ++++++++++++++++++
target/riscv/cpu.c | 4 +++
target/riscv/cpu.h | 1 +
5 files changed, 89 insertions(+)
diff --git a/linux-user/riscv/cpu_loop.c b/linux-user/riscv/cpu_loop.c
index 52c49c2e42..22670b68e0 100644
--- a/linux-user/riscv/cpu_loop.c
+++ b/linux-user/riscv/cpu_loop.c
@@ -25,6 +25,7 @@
#include "signal-common.h"
#include "elf.h"
#include "semihosting/common-semi.h"
+#include "user-mmap.h"
void cpu_loop(CPURISCVState *env)
{
@@ -94,6 +95,55 @@ void cpu_loop(CPURISCVState *env)
}
}
+#define ZICFISS_GUARD_SIZE (2UL * TARGET_PAGE_SIZE)
+#define ZICFISS_STACK_SIZE (16UL * TARGET_PAGE_SIZE)
+#define ZICFISS_THREAD_SIZE (ZICFISS_STACK_SIZE + ZICFISS_GUARD_SIZE)
+
+void zicfiss_shadow_stack_alloc(CPUArchState *env)
+{
+ uintptr_t new_base;
+
+ /* SS page should be surrounded by two guard pages */
+ new_base = (uintptr_t) target_mmap(0, ZICFISS_THREAD_SIZE, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if ((intptr_t)new_base == -1) {
+ perror("shadow stack alloc failure");
+ exit(EXIT_FAILURE);
+ }
+ new_base += TARGET_PAGE_SIZE;
+ int ret = mprotect((void *)new_base, ZICFISS_STACK_SIZE,
+ PROT_READ | PROT_WRITE);
+ if (ret == -1) {
+ perror("shadow stack mprotect failure");
+ exit(EXIT_FAILURE);
+ }
+
+ env->ssp_base = new_base;
+ env->ssp = new_base + ZICFISS_STACK_SIZE;
+}
+
+void zicfiss_shadow_stack_release(CPUArchState *env)
+{
+ abi_ulong mmap_base;
+
+ if (env->ssp == 0) {
+ perror("release empty shadow stack");
+ exit(EXIT_FAILURE);
+ }
+
+ /* It should match shadow stack allocation. */
+ mmap_base = env->ssp_base - TARGET_PAGE_SIZE;
+
+ int ret = target_munmap(mmap_base, ZICFISS_THREAD_SIZE);
+ if (ret == -1) {
+ perror("shadow stack release failure");
+ exit(EXIT_FAILURE);
+ }
+
+ env->ssp_base = 0;
+ env->ssp = 0;
+}
+
void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
{
CPUState *cpu = env_cpu(env);
diff --git a/linux-user/riscv/target_cpu.h b/linux-user/riscv/target_cpu.h
index 9c642367a3..bba54d93eb 100644
--- a/linux-user/riscv/target_cpu.h
+++ b/linux-user/riscv/target_cpu.h
@@ -1,6 +1,9 @@
#ifndef RISCV_TARGET_CPU_H
#define RISCV_TARGET_CPU_H
+extern void zicfiss_shadow_stack_alloc(CPUArchState *env);
+extern void zicfiss_shadow_stack_release(CPUArchState *env);
+
static inline void cpu_clone_regs_child(CPURISCVState *env, target_ulong newsp,
unsigned flags)
{
@@ -9,6 +12,10 @@ static inline void cpu_clone_regs_child(CPURISCVState *env, target_ulong newsp,
}
env->gpr[xA0] = 0;
+
+ if (flags & CLONE_VM) {
+ zicfiss_shadow_stack_alloc(env);
+ }
}
static inline void cpu_clone_regs_parent(CPURISCVState *env, unsigned flags)
diff --git a/linux-user/riscv/target_prctl.h b/linux-user/riscv/target_prctl.h
index d7f9f954c9..6293d61519 100644
--- a/linux-user/riscv/target_prctl.h
+++ b/linux-user/riscv/target_prctl.h
@@ -13,6 +13,33 @@ static abi_long do_prctl_cfi(CPUArchState *env,
if (env_archcpu(env)->cfg.ext_zicfilp) {
switch (option) {
+ case PR_GET_SHADOW_STACK_STATUS:
+ abi_ulong bcfi_status = 0;
+ /* indirect branch tracking is enabled on the task or not */
+ bcfi_status |= (env->ubcfien ? PR_INDIR_BR_LP_ENABLE : 0);
+ return copy_to_user(flag, &bcfi_status, sizeof(bcfi_status)) ? \
+ -EFAULT : 0;
+
+ case PR_SET_SHADOW_STACK_STATUS:
+ /* if any other bit is set, its invalid param */
+ if (flag & ~PR_SHADOW_STACK_ENABLE) {
+ return -TARGET_EINVAL;
+ }
+
+ if ((flag & PR_SHADOW_STACK_ENABLE)
+ && (env->ssp == 0 && !env->ubcfien)) {
+ zicfiss_shadow_stack_alloc(env);
+ } else {
+ zicfiss_shadow_stack_release(env);
+ }
+ env->ubcfien = (flag & PR_SHADOW_STACK_ENABLE);
+ tb_flush(env_cpu(env));
+ return 0;
+
+ /* locking not implemented (also not needed for qemu-user) yet */
+ case PR_LOCK_SHADOW_STACK_STATUS:
+ return -TARGET_EINVAL;
+
case PR_GET_INDIR_BR_LP_STATUS:
abi_ulong fcfi_status = 0;
/* indirect branch tracking is enabled on the task or not */
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e1ff246c24..5a34eee10c 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1001,6 +1001,10 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
/* on reset ssp is set to 0 */
env->ssp = 0;
+#ifdef CONFIG_USER_ONLY
+ env->ssp_base = 0;
+#endif
+
/*
* 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 82475490ab..af89fc1268 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -232,6 +232,7 @@ struct CPUArchState {
uint32_t elf_flags;
bool ufcfien;
bool ubcfien;
+ target_ulong ssp_base;
#endif
#ifndef CONFIG_USER_ONLY
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 19/24] disas/riscv: enable disassembly for zicfiss instructions
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (17 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 18/24] linux-user/riscv: setup/teardown zicfiss shadow stack for qemu-user Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 20/24] disas/riscv: enable disassembly for compressed sspush/sspopchk Deepak Gupta
` (4 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Enable disassembly for sspush, sspopchk, ssrdp & ssamoswap.
Disasembly is only enabled if zimop and zicfiss ext is set to true.
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
disas/riscv.c | 34 ++++++++++++++++++++++++++++++++++
disas/riscv.h | 1 +
2 files changed, 35 insertions(+)
diff --git a/disas/riscv.c b/disas/riscv.c
index c7c92acef7..c4e47fbc78 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -975,6 +975,11 @@ typedef enum {
rv_op_amocas_b = 944,
rv_op_amocas_h = 945,
rv_op_lpad = 946,
+ rv_op_sspush = 947,
+ rv_op_sspopchk = 948,
+ rv_op_ssrdp = 949,
+ rv_op_ssamoswap_w = 950,
+ rv_op_ssamoswap_d = 951,
} rv_op;
/* register names */
@@ -2234,6 +2239,11 @@ const rv_opcode_data rvi_opcode_data[] = {
{ "amocas.b", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
{ "amocas.h", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
{ "lpad", rv_codec_lp, rv_fmt_imm, NULL, 0, 0, 0 },
+ { "sspush", rv_codec_r, rv_fmt_rs2, NULL, 0, 0, 0 },
+ { "sspopchk", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
+ { "ssrdp", rv_codec_r, rv_fmt_rd, NULL, 0, 0, 0 },
+ { "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
};
/* CSR names */
@@ -2251,6 +2261,7 @@ static const char *csr_name(int csrno)
case 0x0009: return "vxsat";
case 0x000a: return "vxrm";
case 0x000f: return "vcsr";
+ case 0x0011: return "ssp";
case 0x0015: return "seed";
case 0x0017: return "jvt";
case 0x0040: return "uscratch";
@@ -3077,6 +3088,8 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 66: op = rv_op_amoor_w; break;
case 67: op = rv_op_amoor_d; break;
case 68: op = rv_op_amoor_q; break;
+ case 74: op = rv_op_ssamoswap_w; break;
+ case 75: op = rv_op_ssamoswap_d; break;
case 96: op = rv_op_amoand_b; break;
case 97: op = rv_op_amoand_h; break;
case 98: op = rv_op_amoand_w; break;
@@ -4036,11 +4049,32 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
extract32(inst, 26, 2)),
4, 1, extract32(inst, 30, 1));
op = rv_mop_r_0 + imm_mop5;
+ /* if zicfiss enabled and mop5 is shadow stack */
+ if (dec->cfg->ext_zicfiss &&
+ ((imm_mop5 & 0b11100) == 0b11100)) {
+ /* rs1=0 means ssrdp */
+ if ((inst & (0b011111 << 15)) == 0) {
+ op = rv_op_ssrdp;
+ }
+ /* rd=0 means sspopchk */
+ if ((inst & (0b011111 << 7)) == 0) {
+ op = rv_op_sspopchk;
+ }
+ }
} else if ((extract32(inst, 25, 7) & 0b1011001)
== 0b1000001) {
imm_mop3 = deposit32(extract32(inst, 26, 2),
2, 1, extract32(inst, 30, 1));
op = rv_mop_rr_0 + imm_mop3;
+ /* if zicfiss enabled and mop3 is shadow stack */
+ if (dec->cfg->ext_zicfiss &&
+ ((imm_mop3 & 0b111) == 0b111)) {
+ /* rs1=0 and rd=0 means sspush */
+ if (((inst & (0b011111 << 15)) == 0) &&
+ ((inst & (0b011111 << 7)) == 0)) {
+ op = rv_op_sspush;
+ }
+ }
}
}
break;
diff --git a/disas/riscv.h b/disas/riscv.h
index 1182457aff..4895c5a301 100644
--- a/disas/riscv.h
+++ b/disas/riscv.h
@@ -224,6 +224,7 @@ enum {
#define rv_fmt_none "O\t"
#define rv_fmt_rs1 "O\t1"
+#define rv_fmt_rs2 "O\t2"
#define rv_fmt_offset "O\to"
#define rv_fmt_pred_succ "O\tp,s"
#define rv_fmt_rs1_rs2 "O\t1,2"
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 20/24] disas/riscv: enable disassembly for compressed sspush/sspopchk
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (18 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 19/24] disas/riscv: enable disassembly for zicfiss instructions Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 21/24] target/riscv: add trace-hooks for each case of sw-check exception Deepak Gupta
` (3 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
sspush and sspopchk have equivalent compressed encoding taken from zcmop.
cmop.1 is sspush x1 while cmop.5 is sspopchk x5. Due to unusual encoding
for both rs1 and rs2 from space bitfield, this required a new codec.
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
disas/riscv.c | 19 ++++++++++++++++++-
disas/riscv.h | 1 +
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/disas/riscv.c b/disas/riscv.c
index c4e47fbc78..82175e75ee 100644
--- a/disas/riscv.c
+++ b/disas/riscv.c
@@ -980,6 +980,8 @@ typedef enum {
rv_op_ssrdp = 949,
rv_op_ssamoswap_w = 950,
rv_op_ssamoswap_d = 951,
+ rv_op_c_sspush = 952,
+ rv_op_c_sspopchk = 953,
} rv_op;
/* register names */
@@ -2244,6 +2246,10 @@ const rv_opcode_data rvi_opcode_data[] = {
{ "ssrdp", rv_codec_r, rv_fmt_rd, NULL, 0, 0, 0 },
{ "ssamoswap.w", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
{ "ssamoswap.d", rv_codec_r_a, rv_fmt_aqrl_rd_rs2_rs1, NULL, 0, 0, 0 },
+ { "c.sspush", rv_codec_cmop_ss, rv_fmt_rs2, NULL, rv_op_sspush,
+ rv_op_sspush, 0 },
+ { "c.sspopchk", rv_codec_cmop_ss, rv_fmt_rs1, NULL, rv_op_sspopchk,
+ rv_op_sspopchk, 0 },
};
/* CSR names */
@@ -2604,7 +2610,13 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
if (dec->cfg->ext_zcmop) {
if ((((inst >> 2) & 0b111111) == 0b100000) &&
(((inst >> 11) & 0b11) == 0b0)) {
- op = rv_c_mop_1 + ((inst >> 8) & 0b111);
+ unsigned int cmop_code = 0;
+ cmop_code = ((inst >> 8) & 0b111);
+ op = rv_c_mop_1 + cmop_code;
+ if (dec->cfg->ext_zicfiss) {
+ op = (cmop_code == 0) ? rv_op_c_sspush : op;
+ op = (cmop_code == 2) ? rv_op_c_sspopchk : op;
+ }
break;
}
}
@@ -4919,6 +4931,11 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa)
case rv_codec_lp:
dec->imm = operand_lpl(inst);
break;
+ case rv_codec_cmop_ss:
+ dec->rd = rv_ireg_zero;
+ dec->rs1 = dec->rs2 = operand_crs1(inst);
+ dec->imm = 0;
+ break;
};
}
diff --git a/disas/riscv.h b/disas/riscv.h
index 4895c5a301..6a3b371cd3 100644
--- a/disas/riscv.h
+++ b/disas/riscv.h
@@ -167,6 +167,7 @@ typedef enum {
rv_codec_r2_imm2_imm5,
rv_codec_fli,
rv_codec_lp,
+ rv_codec_cmop_ss,
} rv_codec;
/* structures */
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 21/24] target/riscv: add trace-hooks for each case of sw-check exception
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (19 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 20/24] disas/riscv: enable disassembly for compressed sspush/sspopchk Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 22/24] linux-user: permit RISC-V CFI dynamic entry in VDSO Deepak Gupta
` (2 subsequent siblings)
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Violations to control flow rules setup by zicfilp and zicfiss lead to
software check exceptions. To debug and fix such sw check issues in guest
, add trace-hooks for each case.
Signed-off-by: Jim Shu <jim.shu@sifive.com>
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
target/riscv/insn_trans/trans_rvi.c.inc | 1 +
target/riscv/op_helper.c | 4 ++++
target/riscv/trace-events | 6 ++++++
target/riscv/translate.c | 2 ++
4 files changed, 13 insertions(+)
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index ee868c5fcb..66b26cbe8b 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -65,6 +65,7 @@ static bool trans_lpad(DisasContext *ctx, arg_lpad *a)
tcg_constant_tl(RISCV_EXCP_SW_CHECK_FCFI_TVAL),
tcg_env, offsetof(CPURISCVState, sw_check_code));
generate_exception(ctx, RISCV_EXCP_SW_CHECK);
+ trace_zicfilp_unaligned_lpad_instr((uint64_t) ctx->base.pc_next);
return true;
}
}
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 54baa3a966..6a54c6c24d 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -24,6 +24,7 @@
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/helper-proto.h"
+#include "trace.h"
/* Exceptions processing helpers */
G_NORETURN void riscv_raise_exception(CPURISCVState *env,
@@ -283,6 +284,8 @@ void helper_cfi_check_landing_pad(CPURISCVState *env, int lbl)
* greater than 31 and then shift 12 right
*/
if (lbl && (lbl != ((env->gpr[xT2] & 0xFFFFFFFF) >> 12))) {
+ trace_zicfilp_lpad_reg_mismatch(lbl,
+ (env->gpr[xT2] & 0xFFFFFFFF) >> 12);
env->sw_check_code = RISCV_EXCP_SW_CHECK_FCFI_TVAL;
riscv_raise_exception(env, RISCV_EXCP_SW_CHECK, GETPC());
}
@@ -295,6 +298,7 @@ void helper_sschk_mismatch(CPURISCVState *env, target_ulong rs1,
target_ulong ssra)
{
if (rs1 != ssra) {
+ trace_zicfiss_sspopchk_reg_mismatch((uint64_t)ssra, (uint64_t) rs1);
env->sw_check_code = RISCV_EXCP_SW_CHECK_BCFI_TVAL;
riscv_raise_exception(env, RISCV_EXCP_SW_CHECK, GETPC());
}
diff --git a/target/riscv/trace-events b/target/riscv/trace-events
index 49ec4d3b7d..842349ecb9 100644
--- a/target/riscv/trace-events
+++ b/target/riscv/trace-events
@@ -9,3 +9,9 @@ pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %"
mseccfg_csr_read(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": read mseccfg, val: 0x%" PRIx64
mseccfg_csr_write(uint64_t mhartid, uint64_t val) "hart %" PRIu64 ": write mseccfg, val: 0x%" PRIx64
+
+# zicfiss/lp
+zicfiss_sspopchk_reg_mismatch(uint64_t ssra, uint64_t rs1) "shadow_stack_ra: 0x%" PRIx64 ", rs1: 0x%" PRIx64
+zicfilp_missing_lpad_instr(uint64_t pc_first) "pc_first: 0x%" PRIx64
+zicfilp_unaligned_lpad_instr(uint64_t pc_next) "pc_next: 0x%" PRIx64
+zicfilp_lpad_reg_mismatch(int lpad_label, int t2_label) "lpad_label: 0x%x, t2_label: 0x%x"
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index ad0f841807..958a1578d4 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -30,6 +30,7 @@
#include "semihosting/semihost.h"
#include "internals.h"
+#include "trace.h"
#define HELPER_H "helper.h"
#include "exec/helper-info.c.inc"
@@ -1380,6 +1381,7 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
* illegal instruction exception.
*/
tcg_set_insn_param(cfi_lp_check, 1, tcgv_i32_arg(tcg_constant_i32(1)));
+ trace_zicfilp_missing_lpad_instr((uint64_t) ctx->base.pc_first);
}
}
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 22/24] linux-user: permit RISC-V CFI dynamic entry in VDSO
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (20 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 21/24] target/riscv: add trace-hooks for each case of sw-check exception Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 23/24] linux-user: Add RISC-V zicfilp support " Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 24/24] linux-user/riscv: Adding zicfiss/lp extension in hwprobe syscall Deepak Gupta
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
RISC-V CFI use new processor-specific dynamic entry in ELF. Permit it in
VDSO post-processing script.
Signed-off-by: Jim Shu <jim.shu@sifive.com>
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
linux-user/gen-vdso-elfn.c.inc | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/linux-user/gen-vdso-elfn.c.inc b/linux-user/gen-vdso-elfn.c.inc
index 95856eb839..59c818eb11 100644
--- a/linux-user/gen-vdso-elfn.c.inc
+++ b/linux-user/gen-vdso-elfn.c.inc
@@ -273,6 +273,13 @@ static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
errors++;
break;
+ case PT_LOPROC + 2:
+ /* RISCV_ZICFILP_PLT: for RISC-V zicfilp extension */
+ if (ehdr->e_machine == EM_RISCV) {
+ break;
+ }
+ goto do_default;
+
case PT_LOPROC + 3:
if (ehdr->e_machine == EM_PPC64) {
break; /* DT_PPC64_OPT: integer bitmask */
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 23/24] linux-user: Add RISC-V zicfilp support in VDSO
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (21 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 22/24] linux-user: permit RISC-V CFI dynamic entry in VDSO Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
2024-07-29 17:53 ` [PATCH v2 24/24] linux-user/riscv: Adding zicfiss/lp extension in hwprobe syscall Deepak Gupta
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Add zicfilp support in VDSO. VDSO functions need lpad instruction
so that userspace could call this function when landing pad extension is
enabled. This solution only works when toolchain always use landing pad
label 1.
Otherwise, If extension is not enabled, lpad instructions will be lui
instructions with rd=x0 (which is nop). Prebuilt VDSO is still
compatible with RISC-V core w/o zicfilp extension.
Signed-off-by: Jim Shu <jim.shu@sifive.com>
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
linux-user/riscv/vdso-64.so | Bin 3944 -> 4128 bytes
linux-user/riscv/vdso.S | 50 ++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+)
diff --git a/linux-user/riscv/vdso-64.so b/linux-user/riscv/vdso-64.so
index ae49f5b043b5941b9d304a056c2b50c185f413b0..cd7f2fa7bdb811af6be2dcc3fb9601b66e3d1c81 100755
GIT binary patch
delta 1345
zcmah}O=uHA6rRa8*`3W#v-vSWgUvy(QL#}%mV&j76iPuQBHAj2(ng|zmM)E!P>`g>
ziy+eQP!K%yD2kv2Jb7q5_;(V#<f8T>2zrPIp$E0T*_|nLFFu%g^L_K)%k2BfxBcts
zwSKzU%uIMvDl|QN=xp<WSxBkG7O6?t!5&mSxH{CqZapIS5in@ND0&^M9SwtYn2kCl
z8HHvbTIYee+1S|&oZsNl6@EhD=NK-I`TfVcovANRA6MVpdHd;BIWn<tz;C}Zg!f#o
zJIeOs$1M@)*Wc|0j<Y-<ig*^WdPuKL`0SmKqyiq##X<Z^OE9+jz3uoXh2tNAc{aFo
z1twr<QCRm}!4()%@Eu+GDUKoG>4}g4*$}@d(n<~qepB*LP!3)Siz)<!cU)L~kXC{}
zEqLOxKPmXG%f8cUD^<!G_?jY`yo4d|;kbMX*GF*m<L!yoO|MGplL+N?0uP|A=~d*e
zHVAQWSlx}&F5K8<AH_U!-zdg#{GVyuzc7Q_Vx?MIB6I?e-o>SSu5ui{`}Ri4l{qVG
z<))V_rE;ZO#UoHP&Zd{==Wom%v$EK`eUMXAv;*hV1Wm$<8dtCYs1tO{Mm~~-=ZGxa
z<BEpgVQ6uMk)*A4Qbe7gH5*}xprDP>jpj-e9%`|fX?zbQKeuJaBedlj?wn7H+zXnl
z+6N3On@wEY6ZY=Tcmf7X)L-B&?+<q+-wWQ|H=hOXuJ8}RyE}+CAdkP(XK2SI=J0*Q
z-CCqns+~DMS-yO9fgGs8S6}+Sm1w<YuP7ab3>M^(KWxa1Nj(DZ`~!MYOa>phK%U8T
zbfFM1nH*fK8zMQjS!g4|p|!;V8Z`BtS@y!IU|yFKn)JeIFwbQ2i_i|5tR_lP0~#_7
pnM$drU_4|p`G+?Pw?igvKsz+7r*-ESGZggRJRA2r@IJ6$-#>;G!0Z43
delta 1236
zcmZux&1(};5TBP#+z*pYV+<*_)IAj1YN_?B+bY<^rnX2aRgfZHEGbA2QZyn~#MXa6
z69zo>Q1McbLL?%ocu2)V4jv*F!CQ|xnnMLet@AeXqAU))otfYJy|4M$HK*Q{?-jj;
zzFD!24I_@VKv0a~RwP*{I_d3w;EB@E*7O6Uf;7sa>HGB{<AWFz$(R#rvRWEP#3-gj
z=kh_C&}d9dUxAJB?DWLN7i-UF5AA;Y{Ap&b@ba}>XUh-Cou=~6m1b2gB-#DFx9A!2
zLL__`q}b;tKwVy%#A+&d0)Qt2<9$E(n(OP#|HVGj;Vb(!Jnn^O9`m|=HV73ypSJ_~
z<O2|fJRcb5i6e}!D;#fWJy$=lXD}<ltX0Kge2VdkkAIHwS3Z8Z)X;Lmd_cFEA<8=5
z3>{6VtH|v2)99wz{?bNB7jqeM)ifG;D@Xo~6$*{frvJ5_f9#bOCr+W3+&Ha4qi9He
z`aFGZFXXa!K@5`_!U4;{c`Jrnfi7ItJ4G3v>4^@ll@B7dM5F9h@S~p4LQq9vBn42^
z6PgYw(n%q6kkCx1d)fjA=g8j=lUShHyjQ?)jZ>c0vk;|y1vK_lb*f|98Q<a9Dg1<I
z(5|Y4cw(IS{)}HEJVyHiUb5rMGWY&0-6zKXYT_~D{_L$X?yrs_<E<JZU&?zLa(}9t
z4i8YNglu-<^o7ju<$*=$zE^r^y%V@%J9s_Z7E|F+dJrFlk6Efc>H&Nc9x~NiEBHO^
znyS~TI1+KqRtw@1d8*G+xEXP+8h24Gh(97jmTIbc5YN~{ri!eCOSWrHa-1h|({^L3
qZ<NlUh`Ofw^Ne9S>WX$;ijJCP(|ap?q2JVD+=;fE1#ar668QsJ{<Wt7
diff --git a/linux-user/riscv/vdso.S b/linux-user/riscv/vdso.S
index c37275233a..d0817c58ce 100644
--- a/linux-user/riscv/vdso.S
+++ b/linux-user/riscv/vdso.S
@@ -14,6 +14,52 @@
#endif
#include "vdso-asmoffset.h"
+/* GNU_PROPERTY_RISCV64_* macros from elf.h for use in asm code. */
+#define FEATURE_1_AND 0xc0000000
+
+#define GNU_PROPERTY(type, value) \
+ .section .note.gnu.property, "a"; \
+ .p2align 3; \
+ .word 4; \
+ .word 16; \
+ .word 5; \
+ .asciz "GNU"; \
+ .word type; \
+ .word 4; \
+ .word value; \
+ .word 0; \
+ .text
+
+/* Add GNU property note with the supported features to all asm code
+ where sysdep.h is included. */
+#undef __VALUE_FOR_FEATURE_1_AND
+#if defined (__riscv_zicfilp) || defined (__riscv_zicfiss)
+# if defined (__riscv_zicfilp)
+# if defined (__riscv_zicfiss)
+# define __VALUE_FOR_FEATURE_1_AND 0x3
+# else
+# define __VALUE_FOR_FEATURE_1_AND 0x1
+# endif
+# else
+# if defined (__riscv_zicfiss)
+# define __VALUE_FOR_FEATURE_1_AND 0x2
+# else
+# error "What?"
+# endif
+# endif
+#endif
+
+#if defined (__VALUE_FOR_FEATURE_1_AND)
+GNU_PROPERTY (FEATURE_1_AND, __VALUE_FOR_FEATURE_1_AND)
+#endif
+#undef __VALUE_FOR_FEATURE_1_AND
+
+#ifdef __riscv_zicfilp
+# define LPAD lpad 1
+#else
+# define LPAD
+#endif
+
.text
.macro endf name
@@ -29,6 +75,7 @@
.macro vdso_syscall name, nr
\name:
+ LPAD
raw_syscall \nr
ret
endf \name
@@ -36,6 +83,7 @@ endf \name
__vdso_gettimeofday:
.cfi_startproc
+ LPAD
#ifdef __NR_gettimeofday
raw_syscall __NR_gettimeofday
ret
@@ -86,6 +134,7 @@ vdso_syscall __vdso_getcpu, __NR_getcpu
__vdso_flush_icache:
/* qemu does not need to flush the icache */
+ LPAD
li a0, 0
ret
endf __vdso_flush_icache
@@ -181,6 +230,7 @@ endf __vdso_flush_icache
nop
__vdso_rt_sigreturn:
+ LPAD
raw_syscall __NR_rt_sigreturn
endf __vdso_rt_sigreturn
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH v2 24/24] linux-user/riscv: Adding zicfiss/lp extension in hwprobe syscall
2024-07-29 17:53 [PATCH v2 00/24] riscv support for control flow integrity extensions Deepak Gupta
` (22 preceding siblings ...)
2024-07-29 17:53 ` [PATCH v2 23/24] linux-user: Add RISC-V zicfilp support " Deepak Gupta
@ 2024-07-29 17:53 ` Deepak Gupta
23 siblings, 0 replies; 35+ messages in thread
From: Deepak Gupta @ 2024-07-29 17:53 UTC (permalink / raw)
To: qemu-riscv, qemu-devel, jim.shu, andy.chiu, jesse.huang,
kito.cheng
Cc: palmer, Alistair.Francis, laurent, bmeng.cn, liwei1518, dbarboza,
zhiwei_liu, Deepak Gupta
Add zicfiss/lp extensions in the ext0 key of hwprobe syscall.
It is aligned with Linux CFI patchset.
Signed-off-by: Jim Shu <jim.shu@sifive.com>
Signed-off-by: Deepak Gupta <debug@rivosinc.com>
---
linux-user/syscall.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f879be7cfe..f2f2164ee5 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -8882,6 +8882,8 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33)
#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34)
#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35)
+#define RISCV_HWPROBE_EXT_ZICFILP (1ULL << 36)
+#define RISCV_HWPROBE_EXT_ZICFISS (1ULL << 37)
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
@@ -9000,6 +9002,10 @@ static void risc_hwprobe_fill_pairs(CPURISCVState *env,
RISCV_HWPROBE_EXT_ZACAS : 0;
value |= cfg->ext_zicond ?
RISCV_HWPROBE_EXT_ZICOND : 0;
+ value |= cfg->ext_zicfilp ?
+ RISCV_HWPROBE_EXT_ZICFILP : 0;
+ value |= cfg->ext_zicfiss ?
+ RISCV_HWPROBE_EXT_ZICFISS : 0;
__put_user(value, &pair->value);
break;
case RISCV_HWPROBE_KEY_CPUPERF_0:
--
2.44.0
^ permalink raw reply related [flat|nested] 35+ messages in thread