mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
RISC-V: KVM: Make SBI uapi consistent with ISA uapi
When an SBI extension cannot be enabled, that's a distinct state vs. enabled and disabled. Modify enum kvm_riscv_sbi_ext_status to accommodate it, which allows KVM userspace to tell the difference in state too, as the SBI extension register will disappear when it cannot be enabled, i.e. accesses to it return ENOENT. get-reg-list is updated as well to only add SBI extension registers to the list which may be enabled. Returning ENOENT for SBI extension registers which cannot be enabled makes them consistent with ISA extension registers. Any SBI extensions which were enabled by default are still enabled by default, if they can be enabled at all. Signed-off-by: Andrew Jones <ajones@ventanamicro.com> Reviewed-by: Anup Patel <anup@brainfault.org> Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
parent
7602730d7f
commit
23e1dc4502
@ -15,9 +15,10 @@
|
||||
#define KVM_SBI_VERSION_MINOR 0
|
||||
|
||||
enum kvm_riscv_sbi_ext_status {
|
||||
KVM_RISCV_SBI_EXT_UNINITIALIZED,
|
||||
KVM_RISCV_SBI_EXT_AVAILABLE,
|
||||
KVM_RISCV_SBI_EXT_UNAVAILABLE,
|
||||
KVM_RISCV_SBI_EXT_STATUS_UNINITIALIZED,
|
||||
KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE,
|
||||
KVM_RISCV_SBI_EXT_STATUS_ENABLED,
|
||||
KVM_RISCV_SBI_EXT_STATUS_DISABLED,
|
||||
};
|
||||
|
||||
struct kvm_vcpu_sbi_context {
|
||||
@ -36,7 +37,7 @@ struct kvm_vcpu_sbi_extension {
|
||||
unsigned long extid_start;
|
||||
unsigned long extid_end;
|
||||
|
||||
bool default_unavail;
|
||||
bool default_disabled;
|
||||
|
||||
/**
|
||||
* SBI extension handler. It can be defined for a given extension or group of
|
||||
@ -61,6 +62,7 @@ int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu,
|
||||
const struct kvm_one_reg *reg);
|
||||
const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
|
||||
struct kvm_vcpu *vcpu, unsigned long extid);
|
||||
bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx);
|
||||
int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu);
|
||||
|
||||
|
@ -931,27 +931,34 @@ static inline unsigned long num_isa_ext_regs(const struct kvm_vcpu *vcpu)
|
||||
return copy_isa_ext_reg_indices(vcpu, NULL);;
|
||||
}
|
||||
|
||||
static inline unsigned long num_sbi_ext_regs(void)
|
||||
static int copy_sbi_ext_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
||||
{
|
||||
return KVM_RISCV_SBI_EXT_MAX;
|
||||
}
|
||||
unsigned int n = 0;
|
||||
|
||||
static int copy_sbi_ext_reg_indices(u64 __user *uindices)
|
||||
{
|
||||
for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) {
|
||||
u64 size = IS_ENABLED(CONFIG_32BIT) ?
|
||||
KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
|
||||
u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT |
|
||||
KVM_REG_RISCV_SBI_SINGLE | i;
|
||||
|
||||
if (!riscv_vcpu_supports_sbi_ext(vcpu, i))
|
||||
continue;
|
||||
|
||||
if (uindices) {
|
||||
if (put_user(reg, uindices))
|
||||
return -EFAULT;
|
||||
uindices++;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
return num_sbi_ext_regs();
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned long num_sbi_ext_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return copy_sbi_ext_reg_indices(vcpu, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -970,7 +977,7 @@ unsigned long kvm_riscv_vcpu_num_regs(struct kvm_vcpu *vcpu)
|
||||
res += num_fp_f_regs(vcpu);
|
||||
res += num_fp_d_regs(vcpu);
|
||||
res += num_isa_ext_regs(vcpu);
|
||||
res += num_sbi_ext_regs();
|
||||
res += num_sbi_ext_regs(vcpu);
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -1018,7 +1025,7 @@ int kvm_riscv_vcpu_copy_reg_indices(struct kvm_vcpu *vcpu,
|
||||
return ret;
|
||||
uindices += ret;
|
||||
|
||||
ret = copy_sbi_ext_reg_indices(uindices);
|
||||
ret = copy_sbi_ext_reg_indices(vcpu, uindices);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -80,6 +80,34 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct kvm_riscv_sbi_extension_entry *
|
||||
riscv_vcpu_get_sbi_ext(struct kvm_vcpu *vcpu, unsigned long idx)
|
||||
{
|
||||
const struct kvm_riscv_sbi_extension_entry *sext = NULL;
|
||||
|
||||
if (idx >= KVM_RISCV_SBI_EXT_MAX)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
|
||||
if (sbi_ext[i].ext_idx == idx) {
|
||||
sext = &sbi_ext[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sext;
|
||||
}
|
||||
|
||||
bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx)
|
||||
{
|
||||
struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
|
||||
const struct kvm_riscv_sbi_extension_entry *sext;
|
||||
|
||||
sext = riscv_vcpu_get_sbi_ext(vcpu, idx);
|
||||
|
||||
return sext && scontext->ext_status[sext->ext_idx] != KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE;
|
||||
}
|
||||
|
||||
void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run)
|
||||
{
|
||||
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
|
||||
@ -140,28 +168,19 @@ static int riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu *vcpu,
|
||||
unsigned long reg_num,
|
||||
unsigned long reg_val)
|
||||
{
|
||||
unsigned long i;
|
||||
const struct kvm_riscv_sbi_extension_entry *sext = NULL;
|
||||
struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
|
||||
|
||||
if (reg_num >= KVM_RISCV_SBI_EXT_MAX)
|
||||
return -ENOENT;
|
||||
const struct kvm_riscv_sbi_extension_entry *sext;
|
||||
|
||||
if (reg_val != 1 && reg_val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
|
||||
if (sbi_ext[i].ext_idx == reg_num) {
|
||||
sext = &sbi_ext[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sext)
|
||||
sext = riscv_vcpu_get_sbi_ext(vcpu, reg_num);
|
||||
if (!sext || scontext->ext_status[sext->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE)
|
||||
return -ENOENT;
|
||||
|
||||
scontext->ext_status[sext->ext_idx] = (reg_val) ?
|
||||
KVM_RISCV_SBI_EXT_AVAILABLE :
|
||||
KVM_RISCV_SBI_EXT_UNAVAILABLE;
|
||||
KVM_RISCV_SBI_EXT_STATUS_ENABLED :
|
||||
KVM_RISCV_SBI_EXT_STATUS_DISABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -170,24 +189,16 @@ static int riscv_vcpu_get_sbi_ext_single(struct kvm_vcpu *vcpu,
|
||||
unsigned long reg_num,
|
||||
unsigned long *reg_val)
|
||||
{
|
||||
unsigned long i;
|
||||
const struct kvm_riscv_sbi_extension_entry *sext = NULL;
|
||||
struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
|
||||
const struct kvm_riscv_sbi_extension_entry *sext;
|
||||
|
||||
if (reg_num >= KVM_RISCV_SBI_EXT_MAX)
|
||||
return -ENOENT;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
|
||||
if (sbi_ext[i].ext_idx == reg_num) {
|
||||
sext = &sbi_ext[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sext)
|
||||
sext = riscv_vcpu_get_sbi_ext(vcpu, reg_num);
|
||||
if (!sext || scontext->ext_status[sext->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE)
|
||||
return -ENOENT;
|
||||
|
||||
*reg_val = scontext->ext_status[sext->ext_idx] ==
|
||||
KVM_RISCV_SBI_EXT_AVAILABLE;
|
||||
KVM_RISCV_SBI_EXT_STATUS_ENABLED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -325,7 +336,7 @@ const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
|
||||
if (ext->extid_start <= extid && ext->extid_end >= extid) {
|
||||
if (entry->ext_idx >= KVM_RISCV_SBI_EXT_MAX ||
|
||||
scontext->ext_status[entry->ext_idx] ==
|
||||
KVM_RISCV_SBI_EXT_AVAILABLE)
|
||||
KVM_RISCV_SBI_EXT_STATUS_ENABLED)
|
||||
return ext;
|
||||
|
||||
return NULL;
|
||||
@ -413,12 +424,12 @@ void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu)
|
||||
|
||||
if (ext->probe && !ext->probe(vcpu)) {
|
||||
scontext->ext_status[entry->ext_idx] =
|
||||
KVM_RISCV_SBI_EXT_UNAVAILABLE;
|
||||
KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE;
|
||||
continue;
|
||||
}
|
||||
|
||||
scontext->ext_status[entry->ext_idx] = ext->default_unavail ?
|
||||
KVM_RISCV_SBI_EXT_UNAVAILABLE :
|
||||
KVM_RISCV_SBI_EXT_AVAILABLE;
|
||||
scontext->ext_status[entry->ext_idx] = ext->default_disabled ?
|
||||
KVM_RISCV_SBI_EXT_STATUS_DISABLED :
|
||||
KVM_RISCV_SBI_EXT_STATUS_ENABLED;
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +204,6 @@ static int kvm_sbi_ext_dbcn_handler(struct kvm_vcpu *vcpu,
|
||||
const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn = {
|
||||
.extid_start = SBI_EXT_DBCN,
|
||||
.extid_end = SBI_EXT_DBCN,
|
||||
.default_unavail = true,
|
||||
.default_disabled = true,
|
||||
.handler = kvm_sbi_ext_dbcn_handler,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user