[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20260126095504.473371-1-liushuyu@aosc.io>
Date: Mon, 26 Jan 2026 17:55:03 +0800
From: Zixing Liu <liushuyu@...c.io>
To: WANG Xuerui <kernel@...0n.name>,
Huacai Chen <chenhuacai@...nel.org>,
Bibo Mao <maobibo@...ngson.cn>
Cc: Kexy Biscuit <kexybiscuit@...c.io>,
Mingcong Bai <jeffbai@...c.io>,
Zixing Liu <liushuyu@...c.io>,
Paolo Bonzini <pbonzini@...hat.com>,
Jonathan Corbet <corbet@....net>,
Tianrui Zhao <zhaotianrui@...ngson.cn>,
Paul Walmsley <pjw@...nel.org>,
Palmer Dabbelt <palmer@...belt.com>,
Albert Ou <aou@...s.berkeley.edu>,
Alexandre Ghiti <alex@...ti.fr>,
kvm@...r.kernel.org,
linux-doc@...r.kernel.org,
linux-kernel@...r.kernel.org,
loongarch@...ts.linux.dev,
linux-riscv@...ts.infradead.org
Subject: [PATCH v2] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch
This ioctl can be used by the userspace applications to determine which
(special) registers are get/set-able in a meaningful way.
This can be very useful for cross-platform VMMs so that they do not have
to hardcode register indices for each supported architectures.
Signed-off-by: Zixing Liu <liushuyu@...c.io>
---
Documentation/virt/kvm/api.rst | 2 +-
arch/loongarch/kvm/vcpu.c | 85 ++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 01a3abef8abb..f46dd8be282f 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -3603,7 +3603,7 @@ VCPU matching underlying host.
---------------------
:Capability: basic
-:Architectures: arm64, mips, riscv, x86 (if KVM_CAP_ONE_REG)
+:Architectures: arm64, loongarch, mips, riscv, x86 (if KVM_CAP_ONE_REG)
:Type: vcpu ioctl
:Parameters: struct kvm_reg_list (in/out)
:Returns: 0 on success; -1 on error
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 656b954c1134..ed11438f4544 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -1186,6 +1186,73 @@ static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu,
return ret;
}
+static int kvm_loongarch_walk_csrs(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+ unsigned int i, count;
+
+ for (i = 0, count = 0; i < CSR_MAX_NUMS; i++) {
+ if (!(get_gcsr_flag(i) & (SW_GCSR | HW_GCSR)))
+ continue;
+ const u64 reg = KVM_IOC_CSRID(i);
+ if (uindices && put_user(reg, uindices++))
+ return -EFAULT;
+ count++;
+ }
+
+ return count;
+}
+
+static unsigned long kvm_loongarch_num_lbt_regs(void)
+{
+ /* +1 for the LBT_FTOP flag (inside arch.fpu) */
+ return sizeof(struct loongarch_lbt) / sizeof(unsigned long) + 1;
+}
+
+static unsigned long kvm_loongarch_num_regs(struct kvm_vcpu *vcpu)
+{
+ /* +1 for the KVM_REG_LOONGARCH_COUNTER register */
+ unsigned long res =
+ kvm_loongarch_walk_csrs(vcpu, NULL) + KVM_MAX_CPUCFG_REGS + 1;
+
+ if (kvm_guest_has_lbt(&vcpu->arch))
+ res += kvm_loongarch_num_lbt_regs();
+
+ return res;
+}
+
+static int kvm_loongarch_copy_reg_indices(struct kvm_vcpu *vcpu,
+ u64 __user *uindices)
+{
+ u64 reg;
+ unsigned int i;
+
+ i = kvm_loongarch_walk_csrs(vcpu, uindices);
+ if (i < 0)
+ return i;
+ uindices += i;
+
+ for (i = 0; i < KVM_MAX_CPUCFG_REGS; i++) {
+ reg = KVM_IOC_CPUCFG(i);
+ if (put_user(reg, uindices++))
+ return -EFAULT;
+ }
+
+ reg = KVM_REG_LOONGARCH_COUNTER;
+ if (put_user(reg, uindices++))
+ return -EFAULT;
+
+ if (!kvm_guest_has_lbt(&vcpu->arch))
+ return 0;
+
+ for (i = 1; i <= kvm_loongarch_num_lbt_regs(); i++) {
+ reg = (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | i);
+ if (put_user(reg, uindices++))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -1251,6 +1318,24 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = kvm_loongarch_vcpu_set_attr(vcpu, &attr);
break;
}
+ case KVM_GET_REG_LIST: {
+ struct kvm_reg_list __user *user_list = argp;
+ struct kvm_reg_list reg_list;
+ unsigned n;
+
+ r = -EFAULT;
+ if (copy_from_user(®_list, user_list, sizeof(reg_list)))
+ break;
+ n = reg_list.n;
+ reg_list.n = kvm_loongarch_num_regs(vcpu);
+ if (copy_to_user(user_list, ®_list, sizeof(reg_list)))
+ break;
+ r = -E2BIG;
+ if (n < reg_list.n)
+ break;
+ r = kvm_loongarch_copy_reg_indices(vcpu, user_list->reg);
+ break;
+ }
default:
r = -ENOIOCTLCMD;
break;
--
2.52.0
Powered by blists - more mailing lists