Re: [PATCH v2] target/riscv: allow menvcfg/henvcfg LPE and SSE bits on RV32
Daniel Henrique Barboza <[email protected]> Wed, 29 Jul 2026 17:14:29 -0300
| Newsgroups | org.nongnu.qemu-riscv,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
On 7/26/2026 5:05 AM, A-Shehab wrote:
> The Zicfilp landing-pad enable (LPE, bit 2) and Zicfiss shadow-stack
> enable (SSE, bit 3) controls live in the low 32 bits of menvcfg and
> henvcfg, and the CFI specification defines them for both RV32 and RV64.
>
> QEMU only adds MENVCFG_LPE/MENVCFG_SSE (and the henvcfg equivalents) to
> the writable mask inside the "riscv_cpu_mxl(env) == MXL_RV64" block, so
> on RV32 these bits are silently dropped and the features cannot be
> enabled. This is inconsistent with write_senvcfg(), which already
> handles SENVCFG_LPE/SENVCFG_SSE regardless of MXLEN.
>
> Hoist the LPE/SSE mask handling out of the RV64-only block in
> write_menvcfg() and write_henvcfg() so the bits become writable on RV32
> as well. The upper-half writers (write_menvcfgh/write_henvcfgh) are
> unaffected because these bits reside in the low 32 bits.
>
> Reproducible on qemu-system-riscv32 -cpu rv32,zicfilp=true,zicfiss=true:
> an M-mode write of menvcfg.{LPE,SSE} reads back as zero, while the same
> program on rv64 keeps the bits set.
>
> Fixes: 4923f672e3d7 ("target/riscv: Introduce elp state and enabling controls for zicfilp")
> Fixes: 8205bc127a83 ("target/riscv: introduce ssp and enabling controls for zicfiss")
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4045
> Signed-off-by: A-Shehab <[email protected]>
> ---
Reviewed-by: Daniel Henrique Barboza <[email protected]>
> v2: Rebase on current master; the file moved from target/riscv/csr.c to
> target/riscv/tcg/csr.c (noted by Daniel Henrique Barboza). No
> functional change.
>
> v1: https://lore.kernel.org/qemu-devel/[email protected]/
>
> target/riscv/tcg/csr.c | 45 +++++++++++++++++++++++++-----------------
> 1 file changed, 27 insertions(+), 18 deletions(-)
>
> diff --git a/target/riscv/tcg/csr.c b/target/riscv/tcg/csr.c
> index 36f2004bc5..0182e4c408 100644
> --- a/target/riscv/tcg/csr.c
> +++ b/target/riscv/tcg/csr.c
> @@ -3216,6 +3216,19 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
> MENVCFG_CBZE;
> bool stce_changed = false;
>
> + /*
> + * menvcfg.LPE (Zicfilp) and menvcfg.SSE (Zicfiss) reside in the low
> + * 32 bits and are defined for both RV32 and RV64, so they must be
> + * writable regardless of MXLEN.
> + */
> + if (cfg->ext_zicfilp) {
> + mask |= MENVCFG_LPE;
> + }
> +
> + if (cfg->ext_zicfiss) {
> + mask |= MENVCFG_SSE;
> + }
> +
> if (riscv_cpu_mxl(env) == MXL_RV64) {
> mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
> (cfg->ext_sstc ? MENVCFG_STCE : 0) |
> @@ -3223,14 +3236,6 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
> (cfg->ext_svadu ? MENVCFG_ADUE : 0) |
> (cfg->ext_ssdbltrp ? MENVCFG_DTE : 0);
>
> - if (env_archcpu(env)->cfg.ext_zicfilp) {
> - mask |= MENVCFG_LPE;
> - }
> -
> - if (env_archcpu(env)->cfg.ext_zicfiss) {
> - mask |= MENVCFG_SSE;
> - }
> -
> /* Update PMM field only if the value is valid according to Zjpm v1.0 */
> if (env_archcpu(env)->cfg.ext_smnpm &&
> get_field(val, MENVCFG_PMM) != PMM_FIELD_RESERVED) {
> @@ -3378,20 +3383,24 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
> return ret;
> }
>
> + /*
> + * henvcfg.LPE (Zicfilp) and henvcfg.SSE (Zicfiss) reside in the low
> + * 32 bits and are defined for both RV32 and RV64, so they must be
> + * writable regardless of MXLEN.
> + */
> + if (cfg->ext_zicfilp) {
> + mask |= HENVCFG_LPE;
> + }
> +
> + /* H can light up SSE for VS only if HS had it from menvcfg */
> + if (cfg->ext_zicfiss && get_field(env->menvcfg, MENVCFG_SSE)) {
> + mask |= HENVCFG_SSE;
> + }
> +
> if (riscv_cpu_mxl(env) == MXL_RV64) {
> mask |= env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE |
> HENVCFG_DTE);
>
> - 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;
> - }
> -
> /* Update PMM field only if the value is valid according to Zjpm v1.0 */
> if (env_archcpu(env)->cfg.ext_ssnpm &&
> get_field(val, HENVCFG_PMM) != PMM_FIELD_RESERVED) {