mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 14:42:08 +02:00
RISC-V: KVM: add support for FWFT SBI extension
Add basic infrastructure to support the FWFT extension in KVM. Signed-off-by: Clément Léger <cleger@rivosinc.com> Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Atish Patra <atishp@rivosinc.com> Link: https://lore.kernel.org/r/20250523101932.1594077-14-cleger@rivosinc.com Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
parent
76eeb9b8de
commit
6b72fd1705
|
|
@ -21,6 +21,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>
|
||||
|
||||
|
|
@ -263,6 +264,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ 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_susp;
|
||||
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;
|
||||
|
||||
|
|
|
|||
29
arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h
Normal file
29
arch/riscv/include/asm/kvm_vcpu_sbi_fwft.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2025 Rivos Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Clément Léger <cleger@rivosinc.com>
|
||||
*/
|
||||
|
||||
#ifndef __KVM_VCPU_RISCV_FWFT_H
|
||||
#define __KVM_VCPU_RISCV_FWFT_H
|
||||
|
||||
#include <asm/sbi.h>
|
||||
|
||||
struct kvm_sbi_fwft_feature;
|
||||
|
||||
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 */
|
||||
|
|
@ -205,6 +205,7 @@ enum KVM_RISCV_SBI_EXT_ID {
|
|||
KVM_RISCV_SBI_EXT_DBCN,
|
||||
KVM_RISCV_SBI_EXT_STA,
|
||||
KVM_RISCV_SBI_EXT_SUSP,
|
||||
KVM_RISCV_SBI_EXT_FWFT,
|
||||
KVM_RISCV_SBI_EXT_MAX,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ kvm-y += vcpu_onereg.o
|
|||
kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o
|
||||
kvm-y += vcpu_sbi.o
|
||||
kvm-y += vcpu_sbi_base.o
|
||||
kvm-y += vcpu_sbi_fwft.o
|
||||
kvm-y += vcpu_sbi_hsm.o
|
||||
kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_sbi_pmu.o
|
||||
kvm-y += vcpu_sbi_replace.o
|
||||
|
|
|
|||
|
|
@ -78,6 +78,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,
|
||||
|
|
|
|||
216
arch/riscv/kvm/vcpu_sbi_fwft.c
Normal file
216
arch/riscv/kvm/vcpu_sbi_fwft.c
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2025 Rivos Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Clément Léger <cleger@rivosinc.com>
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
struct kvm_sbi_fwft_feature {
|
||||
/**
|
||||
* @id: Feature ID
|
||||
*/
|
||||
enum sbi_fwft_feature_t id;
|
||||
|
||||
/**
|
||||
* @supported: Check if the feature is supported on the vcpu
|
||||
*
|
||||
* This callback is optional, if not provided the feature is assumed to
|
||||
* be supported
|
||||
*/
|
||||
bool (*supported)(struct kvm_vcpu *vcpu);
|
||||
|
||||
/**
|
||||
* @set: Set the feature value
|
||||
*
|
||||
* Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*)
|
||||
*
|
||||
* This callback is mandatory
|
||||
*/
|
||||
long (*set)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long value);
|
||||
|
||||
/**
|
||||
* @get: Get the feature current value
|
||||
*
|
||||
* Return SBI_SUCCESS on success or an SBI error (SBI_ERR_*)
|
||||
*
|
||||
* This callback is mandatory
|
||||
*/
|
||||
long (*get)(struct kvm_vcpu *vcpu, struct kvm_sbi_fwft_config *conf, unsigned long *value);
|
||||
};
|
||||
|
||||
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;
|
||||
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, u32 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, u32 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_LOCKED;
|
||||
|
||||
conf->flags = flags;
|
||||
|
||||
return conf->feature->set(vcpu, conf, value);
|
||||
}
|
||||
|
||||
static int kvm_sbi_fwft_get(struct kvm_vcpu *vcpu, unsigned long 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;
|
||||
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);
|
||||
}
|
||||
|
||||
static void kvm_sbi_ext_fwft_reset(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
int i;
|
||||
struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(features); i++)
|
||||
fwft->configs[i].flags = 0;
|
||||
}
|
||||
|
||||
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,
|
||||
.reset = kvm_sbi_ext_fwft_reset,
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user