diff mbox series

[v9,02/17] target/riscv: Introduce elp state and enabling controls for zicfilp

Message ID 20240826152949.294506-3-debug@rivosinc.com
State New
Headers show
Series riscv support for control flow integrity extensions | expand

Commit Message

Deepak Gupta Aug. 26, 2024, 3:29 p.m. UTC
zicfilp introduces a new state elp ("expected landing pad") in cpu.
During normal execution, elp is idle (NO_LP_EXPECTED) i.e not expecting
landing pad. On an indirect call, elp moves LP_EXPECTED. When elp is
LP_EXPECTED, only a subsquent landing pad instruction can set state back
to NO_LP_EXPECTED. On reset, elp is set to NO_LP_EXPECTED.

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

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

Signed-off-by: Deepak Gupta <debug@rivosinc.com>
Co-developed-by: Jim Shu <jim.shu@sifive.com>
Co-developed-by: Andy Chiu <andy.chiu@sifive.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/riscv/cpu.c      |  3 +++
 target/riscv/cpu.h      |  2 ++
 target/riscv/cpu_bits.h |  6 ++++++
 target/riscv/csr.c      | 31 +++++++++++++++++++++++++++++++
 target/riscv/machine.c  | 19 +++++++++++++++++++
 target/riscv/pmp.c      |  5 +++++
 target/riscv/pmp.h      |  3 ++-
 7 files changed, 68 insertions(+), 1 deletion(-)

Comments

Alistair Francis Aug. 27, 2024, 2:58 a.m. UTC | #1
On Tue, Aug 27, 2024 at 1:30 AM Deepak Gupta <debug@rivosinc.com> wrote:
>
> zicfilp introduces a new state elp ("expected landing pad") in cpu.
> During normal execution, elp is idle (NO_LP_EXPECTED) i.e not expecting
> landing pad. On an indirect call, elp moves LP_EXPECTED. When elp is
> LP_EXPECTED, only a subsquent landing pad instruction can set state back
> to NO_LP_EXPECTED. On reset, elp is set to NO_LP_EXPECTED.
>
> zicfilp is enabled via bit2 in *envcfg CSRs. Enabling control for M-mode
> is in mseccfg CSR at bit position 10.
>
> On trap, elp state is saved away in *status.
> Adds elp to the migration state as well.
>
> Signed-off-by: Deepak Gupta <debug@rivosinc.com>
> Co-developed-by: Jim Shu <jim.shu@sifive.com>
> Co-developed-by: Andy Chiu <andy.chiu@sifive.com>
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/cpu.c      |  3 +++
>  target/riscv/cpu.h      |  2 ++
>  target/riscv/cpu_bits.h |  6 ++++++
>  target/riscv/csr.c      | 31 +++++++++++++++++++++++++++++++
>  target/riscv/machine.c  | 19 +++++++++++++++++++
>  target/riscv/pmp.c      |  5 +++++
>  target/riscv/pmp.h      |  3 ++-
>  7 files changed, 68 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 5dfb3f39ab..8e1f05e5b1 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -994,6 +994,9 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type)
>      /* mmte is supposed to have pm.current hardwired to 1 */
>      env->mmte |= (EXT_STATUS_INITIAL | MMTE_M_PM_CURRENT);
>
> +    /* on reset elp is clear */
> +    env->elp = false;
> +
>      /*
>       * Bits 10, 6, 2 and 12 of mideleg are read only 1 when the Hypervisor
>       * extension is enabled.
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 87742047ce..f966c36a31 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -222,6 +222,8 @@ struct CPUArchState {
>
>      target_ulong jvt;
>
> +    /* elp state for zicfilp extension */
> +    bool      elp;
>  #ifdef CONFIG_USER_ONLY
>      uint32_t elf_flags;
>  #endif
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index c257c5ed7d..b05ebe6f29 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -545,6 +545,8 @@
>  #define MSTATUS_TVM         0x00100000 /* since: priv-1.10 */
>  #define MSTATUS_TW          0x00200000 /* since: priv-1.10 */
>  #define MSTATUS_TSR         0x00400000 /* since: priv-1.10 */
> +#define MSTATUS_SPELP       0x00800000 /* zicfilp */
> +#define MSTATUS_MPELP       0x020000000000 /* zicfilp */
>  #define MSTATUS_GVA         0x4000000000ULL
>  #define MSTATUS_MPV         0x8000000000ULL
>
> @@ -575,6 +577,7 @@ typedef enum {
>  #define SSTATUS_XS          0x00018000
>  #define SSTATUS_SUM         0x00040000 /* since: priv-1.10 */
>  #define SSTATUS_MXR         0x00080000
> +#define SSTATUS_SPELP       MSTATUS_SPELP   /* zicfilp */
>
>  #define SSTATUS64_UXL       0x0000000300000000ULL
>
> @@ -747,6 +750,7 @@ typedef enum RISCVException {
>
>  /* Execution environment configuration bits */
>  #define MENVCFG_FIOM                       BIT(0)
> +#define MENVCFG_LPE                        BIT(2) /* zicfilp */
>  #define MENVCFG_CBIE                       (3UL << 4)
>  #define MENVCFG_CBCFE                      BIT(6)
>  #define MENVCFG_CBZE                       BIT(7)
> @@ -760,11 +764,13 @@ typedef enum RISCVException {
>  #define MENVCFGH_STCE                      BIT(31)
>
>  #define SENVCFG_FIOM                       MENVCFG_FIOM
> +#define SENVCFG_LPE                        MENVCFG_LPE
>  #define SENVCFG_CBIE                       MENVCFG_CBIE
>  #define SENVCFG_CBCFE                      MENVCFG_CBCFE
>  #define SENVCFG_CBZE                       MENVCFG_CBZE
>
>  #define HENVCFG_FIOM                       MENVCFG_FIOM
> +#define HENVCFG_LPE                        MENVCFG_LPE
>  #define HENVCFG_CBIE                       MENVCFG_CBIE
>  #define HENVCFG_CBCFE                      MENVCFG_CBCFE
>  #define HENVCFG_CBZE                       MENVCFG_CBZE
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 432c59dc66..5771a14848 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -1400,6 +1400,11 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
>          }
>      }
>
> +    /* If cfi lp extension is available, then apply cfi lp mask */
> +    if (env_archcpu(env)->cfg.ext_zicfilp) {
> +        mask |= (MSTATUS_MPELP | MSTATUS_SPELP);
> +    }
> +
>      mstatus = (mstatus & ~mask) | (val & mask);
>
>      env->mstatus = mstatus;
> @@ -2101,6 +2106,10 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
>          mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
>                  (cfg->ext_sstc ? MENVCFG_STCE : 0) |
>                  (cfg->ext_svadu ? MENVCFG_ADUE : 0);
> +
> +        if (env_archcpu(env)->cfg.ext_zicfilp) {
> +            mask |= MENVCFG_LPE;
> +        }
>      }
>      env->menvcfg = (env->menvcfg & ~mask) | (val & mask);
>
> @@ -2153,6 +2162,10 @@ static RISCVException write_senvcfg(CPURISCVState *env, int csrno,
>          return ret;
>      }
>
> +    if (env_archcpu(env)->cfg.ext_zicfilp) {
> +        mask |= SENVCFG_LPE;
> +    }
> +
>      env->senvcfg = (env->senvcfg & ~mask) | (val & mask);
>      return RISCV_EXCP_NONE;
>  }
> @@ -2190,6 +2203,10 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
>
>      if (riscv_cpu_mxl(env) == MXL_RV64) {
>          mask |= env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE);
> +
> +        if (env_archcpu(env)->cfg.ext_zicfilp) {
> +            mask |= HENVCFG_LPE;
> +        }
>      }
>
>      env->henvcfg = (env->henvcfg & ~mask) | (val & mask);
> @@ -2654,6 +2671,10 @@ static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno,
>          mask |= SSTATUS64_UXL;
>      }
>
> +    if (env_archcpu(env)->cfg.ext_zicfilp) {
> +        mask |= SSTATUS_SPELP;
> +    }
> +
>      *val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus));
>      return RISCV_EXCP_NONE;
>  }
> @@ -2665,6 +2686,11 @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno,
>      if (env->xl != MXL_RV32 || env->debugger) {
>          mask |= SSTATUS64_UXL;
>      }
> +
> +    if (env_archcpu(env)->cfg.ext_zicfilp) {
> +        mask |= SSTATUS_SPELP;
> +    }
> +
>      /* TODO: Use SXL not MXL. */
>      *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask);
>      return RISCV_EXCP_NONE;
> @@ -2680,6 +2706,11 @@ static RISCVException write_sstatus(CPURISCVState *env, int csrno,
>              mask |= SSTATUS64_UXL;
>          }
>      }
> +
> +    if (env_archcpu(env)->cfg.ext_zicfilp) {
> +        mask |= SSTATUS_SPELP;
> +    }
> +
>      target_ulong newval = (env->mstatus & ~mask) | (val & mask);
>      return write_mstatus(env, CSR_MSTATUS, newval);
>  }
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 76f2150f78..873957c4ab 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -351,6 +351,24 @@ static const VMStateDescription vmstate_jvt = {
>      }
>  };
>
> +static bool elp_needed(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +
> +    return cpu->cfg.ext_zicfilp;
> +}
> +
> +static const VMStateDescription vmstate_elp = {
> +    .name = "cpu/elp",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = elp_needed,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_BOOL(env.elp, RISCVCPU),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  const VMStateDescription vmstate_riscv_cpu = {
>      .name = "cpu",
>      .version_id = 10,
> @@ -423,6 +441,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>          &vmstate_debug,
>          &vmstate_smstateen,
>          &vmstate_jvt,
> +        &vmstate_elp,
>          NULL
>      }
>  };
> diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
> index 9eea397e72..1111d08d08 100644
> --- a/target/riscv/pmp.c
> +++ b/target/riscv/pmp.c
> @@ -598,6 +598,11 @@ void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
>          val &= ~(MSECCFG_MMWP | MSECCFG_MML | MSECCFG_RLB);
>      }
>
> +    /* M-mode forward cfi to be enabled if cfi extension is implemented */
> +    if (env_archcpu(env)->cfg.ext_zicfilp) {
> +        val |= (val & MSECCFG_MLPE);
> +    }
> +
>      env->mseccfg = val;
>  }
>
> diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
> index f5c10ce85c..e0530a17a3 100644
> --- a/target/riscv/pmp.h
> +++ b/target/riscv/pmp.h
> @@ -44,7 +44,8 @@ typedef enum {
>      MSECCFG_MMWP  = 1 << 1,
>      MSECCFG_RLB   = 1 << 2,
>      MSECCFG_USEED = 1 << 8,
> -    MSECCFG_SSEED = 1 << 9
> +    MSECCFG_SSEED = 1 << 9,
> +    MSECCFG_MLPE =  1 << 10,
>  } mseccfg_field_t;
>
>  typedef struct {
> --
> 2.44.0
>
>
diff mbox series

Patch

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5dfb3f39ab..8e1f05e5b1 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -994,6 +994,9 @@  static void riscv_cpu_reset_hold(Object *obj, ResetType type)
     /* mmte is supposed to have pm.current hardwired to 1 */
     env->mmte |= (EXT_STATUS_INITIAL | MMTE_M_PM_CURRENT);
 
+    /* on reset elp is clear */
+    env->elp = false;
+
     /*
      * Bits 10, 6, 2 and 12 of mideleg are read only 1 when the Hypervisor
      * extension is enabled.
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 87742047ce..f966c36a31 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -222,6 +222,8 @@  struct CPUArchState {
 
     target_ulong jvt;
 
+    /* elp state for zicfilp extension */
+    bool      elp;
 #ifdef CONFIG_USER_ONLY
     uint32_t elf_flags;
 #endif
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index c257c5ed7d..b05ebe6f29 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -545,6 +545,8 @@ 
 #define MSTATUS_TVM         0x00100000 /* since: priv-1.10 */
 #define MSTATUS_TW          0x00200000 /* since: priv-1.10 */
 #define MSTATUS_TSR         0x00400000 /* since: priv-1.10 */
+#define MSTATUS_SPELP       0x00800000 /* zicfilp */
+#define MSTATUS_MPELP       0x020000000000 /* zicfilp */
 #define MSTATUS_GVA         0x4000000000ULL
 #define MSTATUS_MPV         0x8000000000ULL
 
@@ -575,6 +577,7 @@  typedef enum {
 #define SSTATUS_XS          0x00018000
 #define SSTATUS_SUM         0x00040000 /* since: priv-1.10 */
 #define SSTATUS_MXR         0x00080000
+#define SSTATUS_SPELP       MSTATUS_SPELP   /* zicfilp */
 
 #define SSTATUS64_UXL       0x0000000300000000ULL
 
@@ -747,6 +750,7 @@  typedef enum RISCVException {
 
 /* Execution environment configuration bits */
 #define MENVCFG_FIOM                       BIT(0)
+#define MENVCFG_LPE                        BIT(2) /* zicfilp */
 #define MENVCFG_CBIE                       (3UL << 4)
 #define MENVCFG_CBCFE                      BIT(6)
 #define MENVCFG_CBZE                       BIT(7)
@@ -760,11 +764,13 @@  typedef enum RISCVException {
 #define MENVCFGH_STCE                      BIT(31)
 
 #define SENVCFG_FIOM                       MENVCFG_FIOM
+#define SENVCFG_LPE                        MENVCFG_LPE
 #define SENVCFG_CBIE                       MENVCFG_CBIE
 #define SENVCFG_CBCFE                      MENVCFG_CBCFE
 #define SENVCFG_CBZE                       MENVCFG_CBZE
 
 #define HENVCFG_FIOM                       MENVCFG_FIOM
+#define HENVCFG_LPE                        MENVCFG_LPE
 #define HENVCFG_CBIE                       MENVCFG_CBIE
 #define HENVCFG_CBCFE                      MENVCFG_CBCFE
 #define HENVCFG_CBZE                       MENVCFG_CBZE
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 432c59dc66..5771a14848 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1400,6 +1400,11 @@  static RISCVException write_mstatus(CPURISCVState *env, int csrno,
         }
     }
 
+    /* If cfi lp extension is available, then apply cfi lp mask */
+    if (env_archcpu(env)->cfg.ext_zicfilp) {
+        mask |= (MSTATUS_MPELP | MSTATUS_SPELP);
+    }
+
     mstatus = (mstatus & ~mask) | (val & mask);
 
     env->mstatus = mstatus;
@@ -2101,6 +2106,10 @@  static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
         mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
                 (cfg->ext_sstc ? MENVCFG_STCE : 0) |
                 (cfg->ext_svadu ? MENVCFG_ADUE : 0);
+
+        if (env_archcpu(env)->cfg.ext_zicfilp) {
+            mask |= MENVCFG_LPE;
+        }
     }
     env->menvcfg = (env->menvcfg & ~mask) | (val & mask);
 
@@ -2153,6 +2162,10 @@  static RISCVException write_senvcfg(CPURISCVState *env, int csrno,
         return ret;
     }
 
+    if (env_archcpu(env)->cfg.ext_zicfilp) {
+        mask |= SENVCFG_LPE;
+    }
+
     env->senvcfg = (env->senvcfg & ~mask) | (val & mask);
     return RISCV_EXCP_NONE;
 }
@@ -2190,6 +2203,10 @@  static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
 
     if (riscv_cpu_mxl(env) == MXL_RV64) {
         mask |= env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE);
+
+        if (env_archcpu(env)->cfg.ext_zicfilp) {
+            mask |= HENVCFG_LPE;
+        }
     }
 
     env->henvcfg = (env->henvcfg & ~mask) | (val & mask);
@@ -2654,6 +2671,10 @@  static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno,
         mask |= SSTATUS64_UXL;
     }
 
+    if (env_archcpu(env)->cfg.ext_zicfilp) {
+        mask |= SSTATUS_SPELP;
+    }
+
     *val = int128_make128(sstatus, add_status_sd(MXL_RV128, sstatus));
     return RISCV_EXCP_NONE;
 }
@@ -2665,6 +2686,11 @@  static RISCVException read_sstatus(CPURISCVState *env, int csrno,
     if (env->xl != MXL_RV32 || env->debugger) {
         mask |= SSTATUS64_UXL;
     }
+
+    if (env_archcpu(env)->cfg.ext_zicfilp) {
+        mask |= SSTATUS_SPELP;
+    }
+
     /* TODO: Use SXL not MXL. */
     *val = add_status_sd(riscv_cpu_mxl(env), env->mstatus & mask);
     return RISCV_EXCP_NONE;
@@ -2680,6 +2706,11 @@  static RISCVException write_sstatus(CPURISCVState *env, int csrno,
             mask |= SSTATUS64_UXL;
         }
     }
+
+    if (env_archcpu(env)->cfg.ext_zicfilp) {
+        mask |= SSTATUS_SPELP;
+    }
+
     target_ulong newval = (env->mstatus & ~mask) | (val & mask);
     return write_mstatus(env, CSR_MSTATUS, newval);
 }
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 76f2150f78..873957c4ab 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -351,6 +351,24 @@  static const VMStateDescription vmstate_jvt = {
     }
 };
 
+static bool elp_needed(void *opaque)
+{
+    RISCVCPU *cpu = opaque;
+
+    return cpu->cfg.ext_zicfilp;
+}
+
+static const VMStateDescription vmstate_elp = {
+    .name = "cpu/elp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = elp_needed,
+    .fields = (const VMStateField[]) {
+        VMSTATE_BOOL(env.elp, RISCVCPU),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 const VMStateDescription vmstate_riscv_cpu = {
     .name = "cpu",
     .version_id = 10,
@@ -423,6 +441,7 @@  const VMStateDescription vmstate_riscv_cpu = {
         &vmstate_debug,
         &vmstate_smstateen,
         &vmstate_jvt,
+        &vmstate_elp,
         NULL
     }
 };
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 9eea397e72..1111d08d08 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -598,6 +598,11 @@  void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
         val &= ~(MSECCFG_MMWP | MSECCFG_MML | MSECCFG_RLB);
     }
 
+    /* M-mode forward cfi to be enabled if cfi extension is implemented */
+    if (env_archcpu(env)->cfg.ext_zicfilp) {
+        val |= (val & MSECCFG_MLPE);
+    }
+
     env->mseccfg = val;
 }
 
diff --git a/target/riscv/pmp.h b/target/riscv/pmp.h
index f5c10ce85c..e0530a17a3 100644
--- a/target/riscv/pmp.h
+++ b/target/riscv/pmp.h
@@ -44,7 +44,8 @@  typedef enum {
     MSECCFG_MMWP  = 1 << 1,
     MSECCFG_RLB   = 1 << 2,
     MSECCFG_USEED = 1 << 8,
-    MSECCFG_SSEED = 1 << 9
+    MSECCFG_SSEED = 1 << 9,
+    MSECCFG_MLPE =  1 << 10,
 } mseccfg_field_t;
 
 typedef struct {