Hi Clément, This looks good to me, but will need changes for the updated semantics of the LOCK flag. One minor comment below. On 2025-01-06 9:48 AM, Clément Léger wrote: > Add basic infrastructure to support the FWFT extension in KVM. > > Signed-off-by: Clément Léger <cleger@xxxxxxxxxxxx> > --- > arch/riscv/include/asm/kvm_host.h | 4 + > arch/riscv/include/asm/kvm_vcpu_sbi.h | 1 + > arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h | 37 +++++ > arch/riscv/include/uapi/asm/kvm.h | 1 + > arch/riscv/kvm/Makefile | 1 + > arch/riscv/kvm/vcpu_sbi.c | 4 + > arch/riscv/kvm/vcpu_sbi_fwft.c | 176 +++++++++++++++++++++ > 7 files changed, 224 insertions(+) > create mode 100644 arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h > create mode 100644 arch/riscv/kvm/vcpu_sbi_fwft.c > > diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h > index 35eab6e0f4ae..9bd046ed7907 100644 > --- a/arch/riscv/include/asm/kvm_host.h > +++ b/arch/riscv/include/asm/kvm_host.h > @@ -19,6 +19,7 @@ > #include <asm/kvm_vcpu_fp.h> > #include <asm/kvm_vcpu_insn.h> > #include <asm/kvm_vcpu_sbi.h> > +#include <asm/kvm_vcpu_sbi_fwft.h> > #include <asm/kvm_vcpu_timer.h> > #include <asm/kvm_vcpu_pmu.h> > > @@ -276,6 +277,9 @@ struct kvm_vcpu_arch { > /* Performance monitoring context */ > struct kvm_pmu pmu_context; > > + /* Firmware feature SBI extension context */ > + struct kvm_sbi_fwft fwft_context; > + > /* 'static' configurations which are set only once */ > struct kvm_vcpu_config cfg; > > diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h > index 8c465ce90e73..7ff200a1ad3b 100644 > --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h > +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h > @@ -95,6 +95,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst; > extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm; > extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn; > extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta; > +extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft; > extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental; > extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor; > > diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h > new file mode 100644 > index 000000000000..5782517f6e08 > --- /dev/null > +++ b/arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h > @@ -0,0 +1,37 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * Copyright (c) 2025 Rivos Inc. > + * > + * Authors: > + * Clément Léger <cleger@xxxxxxxxxxxx> > + */ > + > +#ifndef __KVM_VCPU_RISCV_FWFT_H > +#define __KVM_VCPU_RISCV_FWFT_H > + > +#include <asm/sbi.h> > + > +struct kvm_sbi_fwft_config; > +struct kvm_vcpu; > + > +struct kvm_sbi_fwft_feature { > + enum sbi_fwft_feature_t id; > + bool (*supported)(struct kvm_vcpu *vcpu); > + int (*set)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long value); > + int (*get)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long *value); > +}; > + > +struct kvm_sbi_fwft_config { > + const struct kvm_sbi_fwft_feature *feature; > + bool supported; > + unsigned long flags; > +}; > + > +/* FWFT data structure per vcpu */ > +struct kvm_sbi_fwft { > + struct kvm_sbi_fwft_config *configs; > +}; > + > +#define vcpu_to_fwft(vcpu) (&(vcpu)->arch.fwft_context) > + > +#endif /* !__KVM_VCPU_RISCV_FWFT_H */ > diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h > index 3482c9a73d1b..0813145a6272 100644 > --- a/arch/riscv/include/uapi/asm/kvm.h > +++ b/arch/riscv/include/uapi/asm/kvm.h > @@ -198,6 +198,7 @@ enum KVM_RISCV_SBI_EXT_ID { > KVM_RISCV_SBI_EXT_VENDOR, > KVM_RISCV_SBI_EXT_DBCN, > KVM_RISCV_SBI_EXT_STA, > + KVM_RISCV_SBI_EXT_FWFT, > KVM_RISCV_SBI_EXT_MAX, > }; > > diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile > index 0fb1840c3e0a..ece6b119913a 100644 > --- a/arch/riscv/kvm/Makefile > +++ b/arch/riscv/kvm/Makefile > @@ -32,6 +32,7 @@ kvm-y += vcpu_sbi_replace.o > kvm-y += vcpu_sbi_sta.o > kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o > kvm-y += vcpu_switch.o > +kvm-y += vcpu_sbi_fwft.o nit: this should go with the other vcpu_sbi_* files. Regards, Samuel > kvm-y += vcpu_timer.o > kvm-y += vcpu_vector.o > kvm-y += vm.o > diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c > index d2dbb0762072..5bf6c92cca5b 100644 > --- a/arch/riscv/kvm/vcpu_sbi.c > +++ b/arch/riscv/kvm/vcpu_sbi.c > @@ -74,6 +74,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = { > .ext_idx = KVM_RISCV_SBI_EXT_STA, > .ext_ptr = &vcpu_sbi_ext_sta, > }, > + { > + .ext_idx = KVM_RISCV_SBI_EXT_FWFT, > + .ext_ptr = &vcpu_sbi_ext_fwft, > + }, > { > .ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL, > .ext_ptr = &vcpu_sbi_ext_experimental, > diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c > new file mode 100644 > index 000000000000..55433e805baa > --- /dev/null > +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c > @@ -0,0 +1,176 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2025 Rivos Inc. > + * > + * Authors: > + * Clément Léger <cleger@xxxxxxxxxxxx> > + */ > + > +#include <linux/errno.h> > +#include <linux/err.h> > +#include <linux/kvm_host.h> > +#include <asm/cpufeature.h> > +#include <asm/sbi.h> > +#include <asm/kvm_vcpu_sbi.h> > +#include <asm/kvm_vcpu_sbi_fwft.h> > + > +static const enum sbi_fwft_feature_t kvm_fwft_defined_features[] = { > + SBI_FWFT_MISALIGNED_EXC_DELEG, > + SBI_FWFT_LANDING_PAD, > + SBI_FWFT_SHADOW_STACK, > + SBI_FWFT_DOUBLE_TRAP, > + SBI_FWFT_PTE_AD_HW_UPDATING, > + SBI_FWFT_POINTER_MASKING_PMLEN, > +}; > + > +static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(kvm_fwft_defined_features); i++) { > + if (kvm_fwft_defined_features[i] == feature) > + return true; > + } > + > + return false; > +} > + > +static const struct kvm_sbi_fwft_feature features[] = { > +}; > + > +static struct kvm_sbi_fwft_config * > +kvm_sbi_fwft_get_config(struct kvm_vcpu *vcpu, enum sbi_fwft_feature_t feature) > +{ > + int i = 0; > + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); > + > + for (i = 0; i < ARRAY_SIZE(features); i++) { > + if (fwft->configs[i].feature->id == feature) > + return &fwft->configs[i]; > + } > + > + return NULL; > +} > + > +static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, > + enum sbi_fwft_feature_t feature, > + struct kvm_sbi_fwft_config **conf) > +{ > + struct kvm_sbi_fwft_config *tconf; > + > + tconf = kvm_sbi_fwft_get_config(vcpu, feature); > + if (!tconf) { > + if (kvm_fwft_is_defined_feature(feature)) > + return SBI_ERR_NOT_SUPPORTED; > + > + return SBI_ERR_DENIED; > + } > + > + if (!tconf->supported) > + return SBI_ERR_NOT_SUPPORTED; > + > + *conf = tconf; > + > + return SBI_SUCCESS; > +} > + > +static int kvm_sbi_fwft_set(struct kvm_vcpu *vcpu, > + enum sbi_fwft_feature_t feature, > + unsigned long value, unsigned long flags) > +{ > + int ret; > + struct kvm_sbi_fwft_config *conf; > + > + ret = kvm_fwft_get_feature(vcpu, feature, &conf); > + if (ret) > + return ret; > + > + if ((flags & ~SBI_FWFT_SET_FLAG_LOCK) != 0) > + return SBI_ERR_INVALID_PARAM; > + > + if (conf->flags & SBI_FWFT_SET_FLAG_LOCK) > + return SBI_ERR_DENIED; > + > + conf->flags = flags; > + > + return conf->feature->set(vcpu, conf, value); > +} > + > +static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, > + enum sbi_fwft_feature_t feature, > + unsigned long *value) > +{ > + int ret; > + struct kvm_sbi_fwft_config *conf; > + > + ret = kvm_fwft_get_feature(vcpu, feature, &conf); > + if (ret) > + return ret; > + > + return conf->feature->get(vcpu, conf, value); > +} > + > +static int kvm_sbi_ext_fwft_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, > + struct kvm_vcpu_sbi_return *retdata) > +{ > + int ret = 0; > + struct kvm_cpu_context *cp = &vcpu->arch.guest_context; > + unsigned long funcid = cp->a6; > + > + switch (funcid) { > + case SBI_EXT_FWFT_SET: > + ret = kvm_sbi_fwft_set(vcpu, cp->a0, cp->a1, cp->a2); > + break; > + case SBI_EXT_FWFT_GET: > + ret = kvm_sbi_fwft_get(vcpu, cp->a0, &retdata->out_val); > + break; > + default: > + ret = SBI_ERR_NOT_SUPPORTED; > + break; > + } > + > + retdata->err_val = ret; > + > + return 0; > +} > + > +static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu) > +{ > + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); > + const struct kvm_sbi_fwft_feature *feature; > + struct kvm_sbi_fwft_config *conf; > + int i; > + > + fwft->configs = kcalloc(ARRAY_SIZE(features), sizeof(struct kvm_sbi_fwft_config), > + GFP_KERNEL); > + if (!fwft->configs) > + return -ENOMEM; > + > + for (i = 0; i < ARRAY_SIZE(features); i++) { > + feature = &features[i]; > + conf = &fwft->configs[i]; > + if (feature->supported) > + conf->supported = feature->supported(vcpu); > + else > + conf->supported = true; > + > + conf->feature = feature; > + } > + > + return 0; > +} > + > +static void kvm_sbi_ext_fwft_deinit(struct kvm_vcpu *vcpu) > +{ > + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); > + > + kfree(fwft->configs); > +} > + > +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft = { > + .extid_start = SBI_EXT_FWFT, > + .extid_end = SBI_EXT_FWFT, > + .handler = kvm_sbi_ext_fwft_handler, > + .init = kvm_sbi_ext_fwft_init, > + .deinit = kvm_sbi_ext_fwft_deinit, > +};