On Mon, Jul 13, 2026 at 6:34 AM Inochi Amaoto <[email protected]> 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 <[email protected]> > Signed-off-by: Quan Zhou <[email protected]> > Signed-off-by: Inochi Amaoto <[email protected]>
LGTM. Reviewed-by: Anup Patel <[email protected]> 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 >

