[PATCH v6 7/8] RISC-V: KVM: Add support for control-flow integrity FWFT features

Anup Patel anup at brainfault.org
Wed Jul 29 06:10:03 PDT 2026


On Mon, Jul 13, 2026 at 6:34 AM Inochi Amaoto <inochiama at gmail.com> wrote:
>
> Control-flow integrity is controlled through a WARL field in henvcfg.
> Expose the feature only if the Zicfilp/Zicfiss is supported for VS-mode.
> Allow the VMM to block access to the feature by disabling the ISA
> extension in the guest.
>
> Assisted-by: YuanSheng:claude-4.7-opus
> Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
> Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup

> ---
>  arch/riscv/include/uapi/asm/kvm.h |   2 +
>  arch/riscv/kvm/vcpu_sbi_fwft.c    | 107 ++++++++++++++++++++++++++++++
>  2 files changed, 109 insertions(+)
>
> diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
> index fd4c81697617..20d9959ca44f 100644
> --- a/arch/riscv/include/uapi/asm/kvm.h
> +++ b/arch/riscv/include/uapi/asm/kvm.h
> @@ -248,6 +248,8 @@ struct kvm_riscv_sbi_fwft {
>         struct kvm_riscv_sbi_fwft_feature misaligned_deleg;
>         struct kvm_riscv_sbi_fwft_feature pointer_masking;
>         struct kvm_riscv_sbi_fwft_feature pte_ad_hw_updating;
> +       struct kvm_riscv_sbi_fwft_feature landing_pad;
> +       struct kvm_riscv_sbi_fwft_feature shadow_stack;
>  };
>
>  /* If you need to interpret the index values, here is the key: */
> diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
> index 4d474a439b29..03153fd8d15f 100644
> --- a/arch/riscv/kvm/vcpu_sbi_fwft.c
> +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
> @@ -176,6 +176,95 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
>         return SBI_SUCCESS;
>  }
>
> +static long kvm_sbi_fwft_set_cfi(struct kvm_vcpu *vcpu,
> +                                struct kvm_sbi_fwft_config *conf,
> +                                bool one_reg_access, unsigned long value,
> +                                u64 flag)
> +{
> +       struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
> +
> +       if (value == 0)
> +               cfg->henvcfg &= ~flag;
> +       else if (value == 1)
> +               cfg->henvcfg |= flag;
> +       else
> +               return SBI_ERR_INVALID_PARAM;
> +
> +       if (cfg->henvcfg & (ENVCFG_LPE | ENVCFG_SSE))
> +               cfg->hedeleg |= BIT(EXC_SOFTWARE_CHECK);
> +       else
> +               cfg->hedeleg &= ~BIT(EXC_SOFTWARE_CHECK);
> +
> +       if (!one_reg_access) {
> +               csr_write(CSR_HEDELEG, cfg->hedeleg);
> +               /*
> +                * Both Bit LPE and SSE are in the lower part, so it is safe
> +                * to only write the henvcfg
> +                */
> +               csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg);
> +       }
> +
> +       return SBI_SUCCESS;
> +}
> +
> +static bool kvm_sbi_fwft_landing_pad_supported(struct kvm_vcpu *vcpu)
> +{
> +       return riscv_isa_extension_available(vcpu->arch.isa, ZICFILP);
> +}
> +
> +static void kvm_sbi_fwft_reset_landing_pad(struct kvm_vcpu *vcpu)
> +{
> +       struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
> +
> +       kvm_sbi_fwft_env_flag_reset_helper(vcpu, ENVCFG_LPE);
> +       if ((cfg->henvcfg & (ENVCFG_LPE | ENVCFG_SSE)) == 0)
> +               cfg->hedeleg &= ~BIT(EXC_SOFTWARE_CHECK);
> +}
> +
> +static long kvm_sbi_fwft_set_landing_pad(struct kvm_vcpu *vcpu,
> +                                        struct kvm_sbi_fwft_config *conf,
> +                                        bool one_reg_access, unsigned long value)
> +{
> +       return kvm_sbi_fwft_set_cfi(vcpu, conf, one_reg_access, value, ENVCFG_LPE);
> +}
> +
> +static long kvm_sbi_fwft_get_landing_pad(struct kvm_vcpu *vcpu,
> +                                        struct kvm_sbi_fwft_config *conf,
> +                                        bool one_reg_access, unsigned long *value)
> +{
> +       return kvm_sbi_fwft_env_flag_get_helper(vcpu, conf, one_reg_access,
> +                                               value, ENVCFG_LPE);
> +}
> +
> +static bool kvm_sbi_fwft_shadow_stack_supported(struct kvm_vcpu *vcpu)
> +{
> +       return riscv_isa_extension_available(vcpu->arch.isa, ZICFISS);
> +}
> +
> +static void kvm_sbi_fwft_reset_shadow_stack(struct kvm_vcpu *vcpu)
> +{
> +       struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
> +
> +       kvm_sbi_fwft_env_flag_reset_helper(vcpu, ENVCFG_SSE);
> +       if ((cfg->henvcfg & (ENVCFG_LPE | ENVCFG_SSE)) == 0)
> +               cfg->hedeleg &= ~BIT(EXC_SOFTWARE_CHECK);
> +}
> +
> +static long kvm_sbi_fwft_set_shadow_stack(struct kvm_vcpu *vcpu,
> +                                         struct kvm_sbi_fwft_config *conf,
> +                                         bool one_reg_access, unsigned long value)
> +{
> +       return kvm_sbi_fwft_set_cfi(vcpu, conf, one_reg_access, value, ENVCFG_SSE);
> +}
> +
> +static long kvm_sbi_fwft_get_shadow_stack(struct kvm_vcpu *vcpu,
> +                                         struct kvm_sbi_fwft_config *conf,
> +                                         bool one_reg_access, unsigned long *value)
> +{
> +       return kvm_sbi_fwft_env_flag_get_helper(vcpu, conf, one_reg_access,
> +                                               value, ENVCFG_SSE);
> +}
> +
>  static bool kvm_sbi_fwft_pte_ad_hw_updating_supported(struct kvm_vcpu *vcpu)
>  {
>         return riscv_isa_extension_available(vcpu->arch.isa, SVADU) &&
> @@ -313,6 +402,24 @@ static const struct kvm_sbi_fwft_feature features[] = {
>                 .set = kvm_sbi_fwft_set_misaligned_delegation,
>                 .get = kvm_sbi_fwft_get_misaligned_delegation,
>         },
> +       {
> +               .id = SBI_FWFT_LANDING_PAD,
> +               .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, landing_pad.enable) /
> +                                sizeof(unsigned long),
> +               .supported = kvm_sbi_fwft_landing_pad_supported,
> +               .reset = kvm_sbi_fwft_reset_landing_pad,
> +               .set = kvm_sbi_fwft_set_landing_pad,
> +               .get = kvm_sbi_fwft_get_landing_pad,
> +       },
> +       {
> +               .id = SBI_FWFT_SHADOW_STACK,
> +               .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, shadow_stack.enable) /
> +                                sizeof(unsigned long),
> +               .supported = kvm_sbi_fwft_shadow_stack_supported,
> +               .reset = kvm_sbi_fwft_reset_shadow_stack,
> +               .set = kvm_sbi_fwft_set_shadow_stack,
> +               .get = kvm_sbi_fwft_get_shadow_stack,
> +       },
>         {
>                 .id = SBI_FWFT_PTE_AD_HW_UPDATING,
>                 .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pte_ad_hw_updating.enable) /
> --
> 2.55.0
>



More information about the linux-riscv mailing list