Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions arch/riscv/kvm/vcpu_sbi_fwft.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ struct kvm_sbi_fwft_feature {
*/
bool (*supported)(struct kvm_vcpu *vcpu);

/**
* @init: Probe and initialize the feature on the vcpu
*
* This callback is optional. If provided, it will be called during
* vcpu initialization to probe the feature availability and perform
* any necessary initialization. Returns true if the feature is supported
* and initialized successfully, false otherwise.
*/
bool (*init)(struct kvm_vcpu *vcpu);

/**
* @reset: Reset the feature value irrespective whether feature is supported or not
*
Expand Down Expand Up @@ -137,10 +147,12 @@ static bool try_to_set_pmm(unsigned long value)

static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu)
{
struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
return riscv_isa_extension_available(vcpu->arch.isa, SMNPM);
}

if (!riscv_isa_extension_available(vcpu->arch.isa, SMNPM))
return false;
static bool kvm_sbi_fwft_pointer_masking_pmlen_init(struct kvm_vcpu *vcpu)
{
struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);

fwft->have_vs_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7);
fwft->have_vs_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16);
Expand Down Expand Up @@ -231,6 +243,7 @@ static const struct kvm_sbi_fwft_feature features[] = {
.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pointer_masking.enable) /
sizeof(unsigned long),
.supported = kvm_sbi_fwft_pointer_masking_pmlen_supported,
.init = kvm_sbi_fwft_pointer_masking_pmlen_init,
.reset = kvm_sbi_fwft_reset_pointer_masking_pmlen,
.set = kvm_sbi_fwft_set_pointer_masking_pmlen,
.get = kvm_sbi_fwft_get_pointer_masking_pmlen,
Expand Down Expand Up @@ -281,6 +294,8 @@ static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature,

if (!tconf->supported || !tconf->enabled)
return SBI_ERR_NOT_SUPPORTED;
else if (tconf->feature->supported && !tconf->feature->supported(vcpu))
return SBI_ERR_NOT_SUPPORTED;

*conf = tconf;

Expand Down Expand Up @@ -365,6 +380,9 @@ static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu)
else
conf->supported = true;

if (conf->supported && feature->init)
conf->supported = feature->init(vcpu);

conf->enabled = conf->supported;
conf->feature = feature;
}
Expand Down Expand Up @@ -408,6 +426,8 @@ static unsigned long kvm_sbi_ext_fwft_get_reg_count(struct kvm_vcpu *vcpu)
conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
if (!conf || !conf->supported)
continue;
else if (conf->feature->supported && !conf->feature->supported(vcpu))
continue;

ret++;
}
Expand All @@ -430,6 +450,8 @@ static int kvm_sbi_ext_fwft_get_reg_id(struct kvm_vcpu *vcpu, int index, u64 *re
conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
if (!conf || !conf->supported)
continue;
else if (conf->feature->supported && !conf->feature->supported(vcpu))
continue;

if (index == idx) {
*reg_id = KVM_REG_RISCV |
Expand Down Expand Up @@ -465,6 +487,8 @@ static int kvm_sbi_ext_fwft_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
if (!conf || !conf->supported)
return -ENOENT;
else if (conf->feature->supported && !conf->feature->supported(vcpu))
return -ENOENT;

switch (reg_num - feature->first_reg_num) {
case 0:
Expand Down Expand Up @@ -502,6 +526,8 @@ static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
if (!conf || !conf->supported)
return -ENOENT;
else if (conf->feature->supported && !conf->feature->supported(vcpu))
return -ENOENT;

switch (reg_num - feature->first_reg_num) {
case 0:
Expand Down
168 changes: 111 additions & 57 deletions tools/testing/selftests/kvm/riscv/get-reg-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ enum {
};

static bool isa_ext_cant_disable[KVM_RISCV_ISA_EXT_MAX];
static bool isa_ext_enabled[KVM_RISCV_ISA_EXT_MAX];
static bool sbi_ext_enabled[KVM_RISCV_SBI_EXT_MAX];

bool check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg)
{
switch (reg & ~REG_MASK) {
case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable):
case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags):
case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value):
return sbi_ext_enabled[KVM_RISCV_SBI_EXT_FWFT] &&
isa_ext_enabled[KVM_RISCV_ISA_EXT_SMNPM];
default:
break;
}

return true;
}

bool filter_reg(__u64 reg)
{
Expand Down Expand Up @@ -149,6 +166,14 @@ bool filter_reg(__u64 reg)
case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1h):
case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio2h):
return isa_ext_cant_disable[KVM_RISCV_ISA_EXT_SSAIA];
/*
* FWFT misaligned delegation registers are always visible when the SBI FWFT
* extension is enable and the host supports the misaligned delegation.
*/
case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable):
case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags):
case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value):
return sbi_ext_enabled[KVM_RISCV_SBI_EXT_FWFT];
default:
break;
}
Expand Down Expand Up @@ -193,24 +218,50 @@ static int override_vector_reg_size(struct kvm_vcpu *vcpu, struct vcpu_reg_subli
return 0;
}

void check_fwft_feature(struct kvm_vcpu *vcpu, struct vcpu_reg_sublist *s, u64 feature)
{
unsigned long value;
int rc;

/* Enable SBI FWFT extension so that we can check the supported register */
rc = __vcpu_set_reg(vcpu, feature, 1);
if (rc)
return;

for (int i = 0; i < s->regs_n; i++) {
if ((s->regs[i] & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_SBI_STATE) {
rc = __vcpu_get_reg(vcpu, s->regs[i], &value);
__TEST_REQUIRE(!rc, "%s not available, skipping tests", s->name);
}
}

/* We should assert if disabling failed here while enabling succeeded before */
vcpu_set_reg(vcpu, feature, 0);
}

void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
{
unsigned long isa_ext_state[KVM_RISCV_ISA_EXT_MAX] = { 0 };
unsigned long isa_ext_state;
struct vcpu_reg_sublist *s;
u64 feature;
int rc;

for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++)
__vcpu_get_reg(vcpu, RISCV_ISA_EXT_REG(i), &isa_ext_state[i]);
for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) {
rc = __vcpu_get_reg(vcpu, RISCV_ISA_EXT_REG(i), &isa_ext_state);
if (!rc)
isa_ext_enabled[i] = !!isa_ext_state;
}

/*
* Disable all extensions which were enabled by default
* if they were available in the risc-v host.
*/
for (int i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) {
rc = __vcpu_set_reg(vcpu, RISCV_ISA_EXT_REG(i), 0);
if (rc && isa_ext_state[i])
if (rc && isa_ext_enabled[i])
isa_ext_cant_disable[i] = true;
else
isa_ext_enabled[i] = false;
}

for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) {
Expand All @@ -232,9 +283,13 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
switch (s->feature_type) {
case VCPU_FEATURE_ISA_EXT:
feature = RISCV_ISA_EXT_REG(s->feature);
isa_ext_enabled[s->feature] = true;
break;
case VCPU_FEATURE_SBI_EXT:
feature = RISCV_SBI_EXT_REG(s->feature);
if (s->feature == KVM_RISCV_SBI_EXT_FWFT)
check_fwft_feature(vcpu, s, feature);
sbi_ext_enabled[s->feature] = true;
break;
default:
TEST_FAIL("Unknown feature type");
Expand Down Expand Up @@ -897,11 +952,15 @@ static __u64 sbi_sta_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_hi),
};

static __u64 sbi_fwft_regs[] = {
static __u64 sbi_fwft_misaligned_deleg_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value),
};

static __u64 sbi_fwft_pointer_masking_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value),
Expand Down Expand Up @@ -1013,7 +1072,7 @@ static __u64 fp_d_regs[] = {
};

/* Define a default vector registers with length. This will be overwritten at runtime */
static __u64 vector_regs[] = {
static __u64 v_regs[] = {
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vstart),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vl),
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vtype),
Expand Down Expand Up @@ -1057,70 +1116,48 @@ static __u64 vector_regs[] = {
#define SUBLIST_BASE \
{"base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), \
.skips_set = base_skips_set, .skips_set_n = ARRAY_SIZE(base_skips_set),}
#define SUBLIST_SBI_BASE \
{"sbi-base", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_V01, \
.regs = sbi_base_regs, .regs_n = ARRAY_SIZE(sbi_base_regs),}
#define SUBLIST_SBI_STA \
{"sbi-sta", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_STA, \
.regs = sbi_sta_regs, .regs_n = ARRAY_SIZE(sbi_sta_regs),}
#define SUBLIST_SBI_FWFT \
{"sbi-fwft", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_FWFT, \
.regs = sbi_fwft_regs, .regs_n = ARRAY_SIZE(sbi_fwft_regs),}
#define SUBLIST_ZICBOM \
{"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),}
#define SUBLIST_ZICBOP \
{"zicbop", .feature = KVM_RISCV_ISA_EXT_ZICBOP, .regs = zicbop_regs, .regs_n = ARRAY_SIZE(zicbop_regs),}
#define SUBLIST_ZICBOZ \
{"zicboz", .feature = KVM_RISCV_ISA_EXT_ZICBOZ, .regs = zicboz_regs, .regs_n = ARRAY_SIZE(zicboz_regs),}
#define SUBLIST_AIA \
{"aia", .feature = KVM_RISCV_ISA_EXT_SSAIA, .regs = aia_regs, .regs_n = ARRAY_SIZE(aia_regs),}
#define SUBLIST_SMSTATEEN \
{"smstateen", .feature = KVM_RISCV_ISA_EXT_SMSTATEEN, .regs = smstateen_regs, .regs_n = ARRAY_SIZE(smstateen_regs),}
#define SUBLIST_FP_F \
{"fp_f", .feature = KVM_RISCV_ISA_EXT_F, .regs = fp_f_regs, \
.regs_n = ARRAY_SIZE(fp_f_regs),}
#define SUBLIST_FP_D \
{"fp_d", .feature = KVM_RISCV_ISA_EXT_D, .regs = fp_d_regs, \
.regs_n = ARRAY_SIZE(fp_d_regs),}

#define SUBLIST_V \
{"v", .feature = KVM_RISCV_ISA_EXT_V, .regs = vector_regs, .regs_n = ARRAY_SIZE(vector_regs),}

#define SUBLIST_ISA(ext, extu) \
{ \
.name = #ext, \
.feature = KVM_RISCV_ISA_EXT_##extu, \
.regs = ext##_regs, \
.regs_n = ARRAY_SIZE(ext##_regs), \
}

#define KVM_ISA_EXT_SIMPLE_CONFIG(ext, extu) \
static __u64 regs_##ext[] = { \
static __u64 ext##_regs[] = { \
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | \
KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | \
KVM_RISCV_ISA_EXT_##extu, \
}; \
static struct vcpu_reg_list config_##ext = { \
.sublists = { \
SUBLIST_BASE, \
{ \
.name = #ext, \
.feature = KVM_RISCV_ISA_EXT_##extu, \
.regs = regs_##ext, \
.regs_n = ARRAY_SIZE(regs_##ext), \
}, \
SUBLIST_ISA(ext, extu), \
{0}, \
}, \
} \

#define SUBLIST_SBI(ext, extu) \
{ \
.name = "sbi-"#ext, \
.feature_type = VCPU_FEATURE_SBI_EXT, \
.feature = KVM_RISCV_SBI_EXT_##extu, \
.regs = sbi_##ext##_regs, \
.regs_n = ARRAY_SIZE(sbi_##ext##_regs), \
}

#define KVM_SBI_EXT_SIMPLE_CONFIG(ext, extu) \
static __u64 regs_sbi_##ext[] = { \
static __u64 sbi_##ext##_regs[] = { \
KVM_REG_RISCV | KVM_REG_SIZE_ULONG | \
KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | \
KVM_RISCV_SBI_EXT_##extu, \
}; \
static struct vcpu_reg_list config_sbi_##ext = { \
.sublists = { \
SUBLIST_BASE, \
{ \
.name = "sbi-"#ext, \
.feature_type = VCPU_FEATURE_SBI_EXT, \
.feature = KVM_RISCV_SBI_EXT_##extu, \
.regs = regs_sbi_##ext, \
.regs_n = ARRAY_SIZE(regs_sbi_##ext), \
}, \
SUBLIST_SBI(ext, extu), \
{0}, \
}, \
} \
Expand All @@ -1129,7 +1166,7 @@ static struct vcpu_reg_list config_sbi_##ext = { \
static struct vcpu_reg_list config_##ext = { \
.sublists = { \
SUBLIST_BASE, \
SUBLIST_##extu, \
SUBLIST_ISA(ext, extu), \
{0}, \
}, \
} \
Expand All @@ -1138,24 +1175,23 @@ static struct vcpu_reg_list config_##ext = { \
static struct vcpu_reg_list config_sbi_##ext = { \
.sublists = { \
SUBLIST_BASE, \
SUBLIST_SBI_##extu, \
SUBLIST_SBI(ext, extu), \
{0}, \
}, \
} \

/* Note: The below list is alphabetically sorted. */

KVM_SBI_EXT_SUBLIST_CONFIG(base, BASE);
KVM_SBI_EXT_SUBLIST_CONFIG(base, V01);
KVM_SBI_EXT_SUBLIST_CONFIG(sta, STA);
KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP);
KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY);
KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT);

KVM_ISA_EXT_SUBLIST_CONFIG(aia, AIA);
KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, FP_F);
KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, FP_D);
KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA);
KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F);
KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, D);
KVM_ISA_EXT_SUBLIST_CONFIG(v, V);
KVM_ISA_EXT_SIMPLE_CONFIG(h, H);
KVM_ISA_EXT_SIMPLE_CONFIG(smnpm, SMNPM);
Expand Down Expand Up @@ -1228,14 +1264,32 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zvksed, ZVKSED);
KVM_ISA_EXT_SIMPLE_CONFIG(zvksh, ZVKSH);
KVM_ISA_EXT_SIMPLE_CONFIG(zvkt, ZVKT);

static struct vcpu_reg_list config_sbi_fwft_misaligned_deleg = {
.sublists = {
SUBLIST_BASE,
SUBLIST_SBI(fwft_misaligned_deleg, FWFT),
{0},
},
};

static struct vcpu_reg_list config_sbi_fwft_pointer_masking = {
.sublists = {
SUBLIST_BASE,
SUBLIST_ISA(smnpm, SMNPM),
SUBLIST_SBI(fwft_pointer_masking, FWFT),
{0},
},
};

struct vcpu_reg_list *vcpu_configs[] = {
&config_sbi_base,
&config_sbi_sta,
&config_sbi_pmu,
&config_sbi_dbcn,
&config_sbi_susp,
&config_sbi_mpxy,
&config_sbi_fwft,
&config_sbi_fwft_misaligned_deleg,
&config_sbi_fwft_pointer_masking,
&config_aia,
&config_fp_f,
&config_fp_d,
Expand Down
Loading