[PATCH] LoongArch: KVM: Add feature passing from user space

From: Bibo Mao
Date: Thu Jun 06 2024 - 03:49:09 EST


Currently features defined in cpucfg CPUCFG_KVM_FEATURE comes from
kvm kernel mode only. Some features are defined in user space VMM,
however KVM module does not know. Here interface is added to update
register CPUCFG_KVM_FEATURE from user space, only bit 24 - 31 is valid.

Feature KVM_LOONGARCH_VCPU_FEAT_VIRT_EXTIOI is added from user mdoe.
FEAT_VIRT_EXTIOI is virt EXTIOI extension which can route interrupt
to 256 VCPUs rather than 4 CPUs like real hw.

Signed-off-by: Bibo Mao <maobibo@xxxxxxxxxxx>
---
arch/loongarch/include/asm/kvm_host.h | 4 +++
arch/loongarch/include/asm/loongarch.h | 5 ++++
arch/loongarch/include/uapi/asm/kvm.h | 2 ++
arch/loongarch/kvm/exit.c | 1 +
arch/loongarch/kvm/vcpu.c | 36 +++++++++++++++++++++++---
5 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 88023ab59486..8fa50d757247 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -135,6 +135,9 @@ enum emulation_result {
#define KVM_LARCH_HWCSR_USABLE (0x1 << 4)
#define KVM_LARCH_LBT (0x1 << 5)

+#define KVM_LOONGARCH_USR_FEAT_MASK \
+ BIT(KVM_LOONGARCH_VCPU_FEAT_VIRT_EXTIOI)
+
struct kvm_vcpu_arch {
/*
* Switch pointer-to-function type to unsigned long
@@ -210,6 +213,7 @@ struct kvm_vcpu_arch {
u64 last_steal;
struct gfn_to_hva_cache cache;
} st;
+ unsigned int usr_features;
};

static inline unsigned long readl_sw_gcsr(struct loongarch_csrs *csr, int reg)
diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
index 7a4633ef284b..4d9837512c19 100644
--- a/arch/loongarch/include/asm/loongarch.h
+++ b/arch/loongarch/include/asm/loongarch.h
@@ -167,9 +167,14 @@

#define CPUCFG_KVM_SIG (CPUCFG_KVM_BASE + 0)
#define KVM_SIGNATURE "KVM\0"
+/*
+ * BIT 24 - 31 is features configurable by user space vmm
+ */
#define CPUCFG_KVM_FEATURE (CPUCFG_KVM_BASE + 4)
#define KVM_FEATURE_IPI BIT(1)
#define KVM_FEATURE_STEAL_TIME BIT(2)
+/* With VIRT_EXTIOI feature, interrupt can route to 256 VCPUs */
+#define KVM_FEATURE_VIRT_EXTIOI BIT(24)

#ifndef __ASSEMBLY__

diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
index ed12e509815c..dd141259de48 100644
--- a/arch/loongarch/include/uapi/asm/kvm.h
+++ b/arch/loongarch/include/uapi/asm/kvm.h
@@ -99,6 +99,8 @@ struct kvm_fpu {

/* Device Control API on vcpu fd */
#define KVM_LOONGARCH_VCPU_CPUCFG 0
+/* For CPUCFG_KVM_FEATURE register */
+#define KVM_LOONGARCH_VCPU_FEAT_VIRT_EXTIOI 24
#define KVM_LOONGARCH_VCPU_PVTIME_CTRL 1
#define KVM_LOONGARCH_VCPU_PVTIME_GPA 0

diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index e1bd81d27fd8..ab2dcc76784a 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -53,6 +53,7 @@ static int kvm_emu_cpucfg(struct kvm_vcpu *vcpu, larch_inst inst)
ret = KVM_FEATURE_IPI;
if (sched_info_on())
ret |= KVM_FEATURE_STEAL_TIME;
+ ret |= vcpu->arch.usr_features;
vcpu->arch.gprs[rd] = ret;
break;
default:
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 3783151fde32..26f2b22b6a62 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -832,6 +832,8 @@ static int kvm_loongarch_cpucfg_has_attr(struct kvm_vcpu *vcpu,
switch (attr->attr) {
case 2:
return 0;
+ case CPUCFG_KVM_FEATURE:
+ return 0;
default:
return -ENXIO;
}
@@ -865,9 +867,18 @@ static int kvm_loongarch_get_cpucfg_attr(struct kvm_vcpu *vcpu,
uint64_t val;
uint64_t __user *uaddr = (uint64_t __user *)attr->addr;

- ret = _kvm_get_cpucfg_mask(attr->attr, &val);
- if (ret)
- return ret;
+ switch (attr->attr) {
+ case 0 ... (KVM_MAX_CPUCFG_REGS - 1):
+ ret = _kvm_get_cpucfg_mask(attr->attr, &val);
+ if (ret)
+ return ret;
+ break;
+ case CPUCFG_KVM_FEATURE:
+ val = vcpu->arch.usr_features & KVM_LOONGARCH_USR_FEAT_MASK;
+ break;
+ default:
+ return -ENXIO;
+ }

put_user(val, uaddr);

@@ -896,7 +907,24 @@ static int kvm_loongarch_vcpu_get_attr(struct kvm_vcpu *vcpu,
static int kvm_loongarch_cpucfg_set_attr(struct kvm_vcpu *vcpu,
struct kvm_device_attr *attr)
{
- return -ENXIO;
+ u64 __user *user = (u64 __user *)attr->addr;
+ u64 val, valid_flags;
+
+ switch (attr->attr) {
+ case CPUCFG_KVM_FEATURE:
+ if (get_user(val, user))
+ return -EFAULT;
+
+ valid_flags = KVM_LOONGARCH_USR_FEAT_MASK;
+ if (val & ~valid_flags)
+ return -EINVAL;
+
+ vcpu->arch.usr_features |= val;
+ return 0;
+
+ default:
+ return -ENXIO;
+ }
}

static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu,

base-commit: 2df0193e62cf887f373995fb8a91068562784adc
--
2.39.3