* [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch @ 2026-02-05 5:18 Zixing Liu 2026-02-10 2:42 ` Bibo Mao 0 siblings, 1 reply; 7+ messages in thread From: Zixing Liu @ 2026-02-05 5:18 UTC (permalink / raw) To: WANG Xuerui, Huacai Chen, Bibo Mao Cc: Kexy Biscuit, Mingcong Bai, Zixing Liu, Paolo Bonzini, Jonathan Corbet, Tianrui Zhao, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm, linux-doc, linux-kernel, loongarch, linux-riscv 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@aosc.io> --- Documentation/virt/kvm/api.rst | 2 +- arch/loongarch/kvm/vcpu.c | 120 +++++++++++++++++++++++++++++++++ 2 files changed, 121 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..de02e409ae39 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -5,6 +5,7 @@ #include <linux/kvm_host.h> #include <asm/fpu.h> +#include <asm/kvm_host.h> #include <asm/lbt.h> #include <asm/loongarch.h> #include <asm/setup.h> @@ -14,6 +15,8 @@ #define CREATE_TRACE_POINTS #include "trace.h" +#define NUM_LBT_REGS 6 + const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { KVM_GENERIC_VCPU_STATS(), STATS_DESC_COUNTER(VCPU, int_exits), @@ -1186,6 +1189,105 @@ 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; + const unsigned int csrs_to_save[] = { + LOONGARCH_CSR_CRMD, LOONGARCH_CSR_PRMD, + LOONGARCH_CSR_EUEN, LOONGARCH_CSR_MISC, + LOONGARCH_CSR_ECFG, LOONGARCH_CSR_ESTAT, + LOONGARCH_CSR_ERA, LOONGARCH_CSR_BADV, + LOONGARCH_CSR_BADI, LOONGARCH_CSR_EENTRY, + LOONGARCH_CSR_TLBIDX, LOONGARCH_CSR_TLBEHI, + LOONGARCH_CSR_TLBELO0, LOONGARCH_CSR_TLBELO1, + LOONGARCH_CSR_ASID, LOONGARCH_CSR_PGDL, + LOONGARCH_CSR_PGDH, LOONGARCH_CSR_PGD, + LOONGARCH_CSR_PWCTL0, LOONGARCH_CSR_PWCTL1, + LOONGARCH_CSR_STLBPGSIZE, LOONGARCH_CSR_RVACFG, + LOONGARCH_CSR_CPUID, LOONGARCH_CSR_PRCFG1, + LOONGARCH_CSR_PRCFG2, LOONGARCH_CSR_PRCFG3, + LOONGARCH_CSR_KS0, LOONGARCH_CSR_KS1, + LOONGARCH_CSR_KS2, LOONGARCH_CSR_KS3, + LOONGARCH_CSR_KS4, LOONGARCH_CSR_KS5, + LOONGARCH_CSR_KS6, LOONGARCH_CSR_KS7, + LOONGARCH_CSR_TMID, LOONGARCH_CSR_CNTC, + LOONGARCH_CSR_TINTCLR, LOONGARCH_CSR_LLBCTL, + LOONGARCH_CSR_IMPCTL1, LOONGARCH_CSR_IMPCTL2, + LOONGARCH_CSR_TLBRENTRY, LOONGARCH_CSR_TLBRBADV, + LOONGARCH_CSR_TLBRERA, LOONGARCH_CSR_TLBRSAVE, + LOONGARCH_CSR_TLBRELO0, LOONGARCH_CSR_TLBRELO1, + LOONGARCH_CSR_TLBREHI, LOONGARCH_CSR_TLBRPRMD, + LOONGARCH_CSR_DMWIN0, LOONGARCH_CSR_DMWIN1, + LOONGARCH_CSR_DMWIN2, LOONGARCH_CSR_DMWIN3, + LOONGARCH_CSR_TVAL, LOONGARCH_CSR_TCFG, + }; + + for (i = 0, count = 0; + i < sizeof(csrs_to_save) / sizeof(csrs_to_save[0]); i++) { + const u64 reg = KVM_IOC_CSRID(i); + if (uindices && put_user(reg, uindices++)) + return -EFAULT; + count++; + } + + /* Skip PMU CSRs if not supported by the guest */ + if (!kvm_guest_has_pmu(&vcpu->arch)) + return count; + for (i = LOONGARCH_CSR_PERFCTRL0; i <= LOONGARCH_CSR_PERFCNTR3; i++) { + const u64 reg = KVM_IOC_CSRID(i); + if (uindices && put_user(reg, uindices++)) + return -EFAULT; + count++; + } + + return count; +} + +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 += 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 <= 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 +1353,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.53.0 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch 2026-02-05 5:18 [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch Zixing Liu @ 2026-02-10 2:42 ` Bibo Mao 2026-02-10 3:23 ` liushuyu 0 siblings, 1 reply; 7+ messages in thread From: Bibo Mao @ 2026-02-10 2:42 UTC (permalink / raw) To: Zixing Liu, WANG Xuerui, Huacai Chen Cc: Kexy Biscuit, Mingcong Bai, Paolo Bonzini, Jonathan Corbet, Tianrui Zhao, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm, linux-doc, linux-kernel, loongarch, linux-riscv On 2026/2/5 下午1:18, Zixing Liu wrote: > 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@aosc.io> > --- > Documentation/virt/kvm/api.rst | 2 +- > arch/loongarch/kvm/vcpu.c | 120 +++++++++++++++++++++++++++++++++ > 2 files changed, 121 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..de02e409ae39 100644 > --- a/arch/loongarch/kvm/vcpu.c > +++ b/arch/loongarch/kvm/vcpu.c > @@ -5,6 +5,7 @@ > > #include <linux/kvm_host.h> > #include <asm/fpu.h> > +#include <asm/kvm_host.h> > #include <asm/lbt.h> > #include <asm/loongarch.h> > #include <asm/setup.h> > @@ -14,6 +15,8 @@ > #define CREATE_TRACE_POINTS > #include "trace.h" > > +#define NUM_LBT_REGS 6 > + > const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { > KVM_GENERIC_VCPU_STATS(), > STATS_DESC_COUNTER(VCPU, int_exits), > @@ -1186,6 +1189,105 @@ 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; > + const unsigned int csrs_to_save[] = { > + LOONGARCH_CSR_CRMD, LOONGARCH_CSR_PRMD, > + LOONGARCH_CSR_EUEN, LOONGARCH_CSR_MISC, > + LOONGARCH_CSR_ECFG, LOONGARCH_CSR_ESTAT, > + LOONGARCH_CSR_ERA, LOONGARCH_CSR_BADV, > + LOONGARCH_CSR_BADI, LOONGARCH_CSR_EENTRY, > + LOONGARCH_CSR_TLBIDX, LOONGARCH_CSR_TLBEHI, > + LOONGARCH_CSR_TLBELO0, LOONGARCH_CSR_TLBELO1, > + LOONGARCH_CSR_ASID, LOONGARCH_CSR_PGDL, > + LOONGARCH_CSR_PGDH, LOONGARCH_CSR_PGD, > + LOONGARCH_CSR_PWCTL0, LOONGARCH_CSR_PWCTL1, > + LOONGARCH_CSR_STLBPGSIZE, LOONGARCH_CSR_RVACFG, > + LOONGARCH_CSR_CPUID, LOONGARCH_CSR_PRCFG1, > + LOONGARCH_CSR_PRCFG2, LOONGARCH_CSR_PRCFG3, > + LOONGARCH_CSR_KS0, LOONGARCH_CSR_KS1, > + LOONGARCH_CSR_KS2, LOONGARCH_CSR_KS3, > + LOONGARCH_CSR_KS4, LOONGARCH_CSR_KS5, > + LOONGARCH_CSR_KS6, LOONGARCH_CSR_KS7, > + LOONGARCH_CSR_TMID, LOONGARCH_CSR_CNTC, > + LOONGARCH_CSR_TINTCLR, LOONGARCH_CSR_LLBCTL, > + LOONGARCH_CSR_IMPCTL1, LOONGARCH_CSR_IMPCTL2, > + LOONGARCH_CSR_TLBRENTRY, LOONGARCH_CSR_TLBRBADV, > + LOONGARCH_CSR_TLBRERA, LOONGARCH_CSR_TLBRSAVE, > + LOONGARCH_CSR_TLBRELO0, LOONGARCH_CSR_TLBRELO1, > + LOONGARCH_CSR_TLBREHI, LOONGARCH_CSR_TLBRPRMD, > + LOONGARCH_CSR_DMWIN0, LOONGARCH_CSR_DMWIN1, > + LOONGARCH_CSR_DMWIN2, LOONGARCH_CSR_DMWIN3, > + LOONGARCH_CSR_TVAL, LOONGARCH_CSR_TCFG, > + }; this increases much kernel stack size usage :) Please wait a moment, I am considering how to cleanup code about CSR registers. And KVM_GET_REG_LIST is not so urgent, else there is KVM_read_from_REG_LIST/KVM_write_from_REG_LIST ioctl commands to access registers in batch mode. Regards Bibo Mao > + > + for (i = 0, count = 0; > + i < sizeof(csrs_to_save) / sizeof(csrs_to_save[0]); i++) { > + const u64 reg = KVM_IOC_CSRID(i); > + if (uindices && put_user(reg, uindices++)) > + return -EFAULT; > + count++; > + } > + > + /* Skip PMU CSRs if not supported by the guest */ > + if (!kvm_guest_has_pmu(&vcpu->arch)) > + return count; > + for (i = LOONGARCH_CSR_PERFCTRL0; i <= LOONGARCH_CSR_PERFCNTR3; i++) { > + const u64 reg = KVM_IOC_CSRID(i); > + if (uindices && put_user(reg, uindices++)) > + return -EFAULT; > + count++; > + } > + > + return count; > +} > + > +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 += 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 <= 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 +1353,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; > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch 2026-02-10 2:42 ` Bibo Mao @ 2026-02-10 3:23 ` liushuyu 2026-02-10 3:43 ` Bibo Mao 0 siblings, 1 reply; 7+ messages in thread From: liushuyu @ 2026-02-10 3:23 UTC (permalink / raw) To: Bibo Mao, WANG Xuerui, Huacai Chen Cc: Kexy Biscuit, Mingcong Bai, Paolo Bonzini, Jonathan Corbet, Tianrui Zhao, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm, linux-doc, linux-kernel, loongarch, linux-riscv Hi Bibo, > > > On 2026/2/5 下午1:18, Zixing Liu wrote: >> 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@aosc.io> >> --- >> Documentation/virt/kvm/api.rst | 2 +- >> arch/loongarch/kvm/vcpu.c | 120 +++++++++++++++++++++++++++++++++ >> 2 files changed, 121 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..de02e409ae39 100644 >> --- a/arch/loongarch/kvm/vcpu.c >> +++ b/arch/loongarch/kvm/vcpu.c >> @@ -5,6 +5,7 @@ >> #include <linux/kvm_host.h> >> #include <asm/fpu.h> >> +#include <asm/kvm_host.h> >> #include <asm/lbt.h> >> #include <asm/loongarch.h> >> #include <asm/setup.h> >> @@ -14,6 +15,8 @@ >> #define CREATE_TRACE_POINTS >> #include "trace.h" >> +#define NUM_LBT_REGS 6 >> + >> const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { >> KVM_GENERIC_VCPU_STATS(), >> STATS_DESC_COUNTER(VCPU, int_exits), >> @@ -1186,6 +1189,105 @@ 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; >> + const unsigned int csrs_to_save[] = { >> + LOONGARCH_CSR_CRMD, LOONGARCH_CSR_PRMD, >> + LOONGARCH_CSR_EUEN, LOONGARCH_CSR_MISC, >> + LOONGARCH_CSR_ECFG, LOONGARCH_CSR_ESTAT, >> + LOONGARCH_CSR_ERA, LOONGARCH_CSR_BADV, >> + LOONGARCH_CSR_BADI, LOONGARCH_CSR_EENTRY, >> + LOONGARCH_CSR_TLBIDX, LOONGARCH_CSR_TLBEHI, >> + LOONGARCH_CSR_TLBELO0, LOONGARCH_CSR_TLBELO1, >> + LOONGARCH_CSR_ASID, LOONGARCH_CSR_PGDL, >> + LOONGARCH_CSR_PGDH, LOONGARCH_CSR_PGD, >> + LOONGARCH_CSR_PWCTL0, LOONGARCH_CSR_PWCTL1, >> + LOONGARCH_CSR_STLBPGSIZE, LOONGARCH_CSR_RVACFG, >> + LOONGARCH_CSR_CPUID, LOONGARCH_CSR_PRCFG1, >> + LOONGARCH_CSR_PRCFG2, LOONGARCH_CSR_PRCFG3, >> + LOONGARCH_CSR_KS0, LOONGARCH_CSR_KS1, >> + LOONGARCH_CSR_KS2, LOONGARCH_CSR_KS3, >> + LOONGARCH_CSR_KS4, LOONGARCH_CSR_KS5, >> + LOONGARCH_CSR_KS6, LOONGARCH_CSR_KS7, >> + LOONGARCH_CSR_TMID, LOONGARCH_CSR_CNTC, >> + LOONGARCH_CSR_TINTCLR, LOONGARCH_CSR_LLBCTL, >> + LOONGARCH_CSR_IMPCTL1, LOONGARCH_CSR_IMPCTL2, >> + LOONGARCH_CSR_TLBRENTRY, LOONGARCH_CSR_TLBRBADV, >> + LOONGARCH_CSR_TLBRERA, LOONGARCH_CSR_TLBRSAVE, >> + LOONGARCH_CSR_TLBRELO0, LOONGARCH_CSR_TLBRELO1, >> + LOONGARCH_CSR_TLBREHI, LOONGARCH_CSR_TLBRPRMD, >> + LOONGARCH_CSR_DMWIN0, LOONGARCH_CSR_DMWIN1, >> + LOONGARCH_CSR_DMWIN2, LOONGARCH_CSR_DMWIN3, >> + LOONGARCH_CSR_TVAL, LOONGARCH_CSR_TCFG, >> + }; > this increases much kernel stack size usage :) > > Please wait a moment, I am considering how to cleanup code about CSR > registers. Okay. > And KVM_GET_REG_LIST is not so urgent, else there is > KVM_read_from_REG_LIST/KVM_write_from_REG_LIST ioctl commands to > access registers in batch mode. > Adding KVM_GET_REG_LIST is not urgent. However, unlike KVM_read_from_REG_LIST and KVM_write_from_REG_LIST, KVM_GET_REG_LIST serves a different purpose. The KVM_GET_REG_LIST ioctl lets user-space VMMs determine the number of get/set-able registers (via KVM_GET_ONE_REG/KVM_SET_ONE_REG) and their register IDs. User-space VMMs use this ioctl so they don't have to hardcode a register ID table for each architecture. I also had trouble finding information on the KVM_read_from_REG_LIST and KVM_write_from_REG_LIST ioctl commands. As of commit 3d29a326eba82d987a82fd59379d6d668b769965, I could not find any logic or identifiers for these two ioctls. In some cases, KVM_GET_REG_LIST is a prerequisite for using KVM_read_from_REG_LIST or KVM_write_from_REG_LIST (assuming they exist), as you still need to know the register IDs to use these ioctls. > Regards > Bibo Mao > >> + >> + for (i = 0, count = 0; >> + i < sizeof(csrs_to_save) / sizeof(csrs_to_save[0]); i++) { >> + const u64 reg = KVM_IOC_CSRID(i); >> + if (uindices && put_user(reg, uindices++)) >> + return -EFAULT; >> + count++; >> + } >> + >> + /* Skip PMU CSRs if not supported by the guest */ >> + if (!kvm_guest_has_pmu(&vcpu->arch)) >> + return count; >> + for (i = LOONGARCH_CSR_PERFCTRL0; i <= LOONGARCH_CSR_PERFCNTR3; >> i++) { >> + const u64 reg = KVM_IOC_CSRID(i); >> + if (uindices && put_user(reg, uindices++)) >> + return -EFAULT; >> + count++; >> + } >> + >> + return count; >> +} >> + >> +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 += 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 <= 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 +1353,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; >> > Thanks, Zixing ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch 2026-02-10 3:23 ` liushuyu @ 2026-02-10 3:43 ` Bibo Mao 2026-02-10 4:05 ` liushuyu 2026-03-09 3:52 ` liushuyu 0 siblings, 2 replies; 7+ messages in thread From: Bibo Mao @ 2026-02-10 3:43 UTC (permalink / raw) To: liushuyu, WANG Xuerui, Huacai Chen Cc: Kexy Biscuit, Mingcong Bai, Paolo Bonzini, Jonathan Corbet, Tianrui Zhao, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm, linux-doc, linux-kernel, loongarch, linux-riscv On 2026/2/10 上午11:23, liushuyu wrote: > Hi Bibo, > >> >> >> On 2026/2/5 下午1:18, Zixing Liu wrote: >>> 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@aosc.io> >>> --- >>> Documentation/virt/kvm/api.rst | 2 +- >>> arch/loongarch/kvm/vcpu.c | 120 +++++++++++++++++++++++++++++++++ >>> 2 files changed, 121 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..de02e409ae39 100644 >>> --- a/arch/loongarch/kvm/vcpu.c >>> +++ b/arch/loongarch/kvm/vcpu.c >>> @@ -5,6 +5,7 @@ >>> #include <linux/kvm_host.h> >>> #include <asm/fpu.h> >>> +#include <asm/kvm_host.h> >>> #include <asm/lbt.h> >>> #include <asm/loongarch.h> >>> #include <asm/setup.h> >>> @@ -14,6 +15,8 @@ >>> #define CREATE_TRACE_POINTS >>> #include "trace.h" >>> +#define NUM_LBT_REGS 6 >>> + >>> const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { >>> KVM_GENERIC_VCPU_STATS(), >>> STATS_DESC_COUNTER(VCPU, int_exits), >>> @@ -1186,6 +1189,105 @@ 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; >>> + const unsigned int csrs_to_save[] = { >>> + LOONGARCH_CSR_CRMD, LOONGARCH_CSR_PRMD, >>> + LOONGARCH_CSR_EUEN, LOONGARCH_CSR_MISC, >>> + LOONGARCH_CSR_ECFG, LOONGARCH_CSR_ESTAT, >>> + LOONGARCH_CSR_ERA, LOONGARCH_CSR_BADV, >>> + LOONGARCH_CSR_BADI, LOONGARCH_CSR_EENTRY, >>> + LOONGARCH_CSR_TLBIDX, LOONGARCH_CSR_TLBEHI, >>> + LOONGARCH_CSR_TLBELO0, LOONGARCH_CSR_TLBELO1, >>> + LOONGARCH_CSR_ASID, LOONGARCH_CSR_PGDL, >>> + LOONGARCH_CSR_PGDH, LOONGARCH_CSR_PGD, >>> + LOONGARCH_CSR_PWCTL0, LOONGARCH_CSR_PWCTL1, >>> + LOONGARCH_CSR_STLBPGSIZE, LOONGARCH_CSR_RVACFG, >>> + LOONGARCH_CSR_CPUID, LOONGARCH_CSR_PRCFG1, >>> + LOONGARCH_CSR_PRCFG2, LOONGARCH_CSR_PRCFG3, >>> + LOONGARCH_CSR_KS0, LOONGARCH_CSR_KS1, >>> + LOONGARCH_CSR_KS2, LOONGARCH_CSR_KS3, >>> + LOONGARCH_CSR_KS4, LOONGARCH_CSR_KS5, >>> + LOONGARCH_CSR_KS6, LOONGARCH_CSR_KS7, >>> + LOONGARCH_CSR_TMID, LOONGARCH_CSR_CNTC, >>> + LOONGARCH_CSR_TINTCLR, LOONGARCH_CSR_LLBCTL, >>> + LOONGARCH_CSR_IMPCTL1, LOONGARCH_CSR_IMPCTL2, >>> + LOONGARCH_CSR_TLBRENTRY, LOONGARCH_CSR_TLBRBADV, >>> + LOONGARCH_CSR_TLBRERA, LOONGARCH_CSR_TLBRSAVE, >>> + LOONGARCH_CSR_TLBRELO0, LOONGARCH_CSR_TLBRELO1, >>> + LOONGARCH_CSR_TLBREHI, LOONGARCH_CSR_TLBRPRMD, >>> + LOONGARCH_CSR_DMWIN0, LOONGARCH_CSR_DMWIN1, >>> + LOONGARCH_CSR_DMWIN2, LOONGARCH_CSR_DMWIN3, >>> + LOONGARCH_CSR_TVAL, LOONGARCH_CSR_TCFG, >>> + }; >> this increases much kernel stack size usage :) >> >> Please wait a moment, I am considering how to cleanup code about CSR >> registers. > Okay. >> And KVM_GET_REG_LIST is not so urgent, else there is >> KVM_read_from_REG_LIST/KVM_write_from_REG_LIST ioctl commands to >> access registers in batch mode. >> > Adding KVM_GET_REG_LIST is not urgent. However, unlike > KVM_read_from_REG_LIST and KVM_write_from_REG_LIST, KVM_GET_REG_LIST > serves a different purpose. > > The KVM_GET_REG_LIST ioctl lets user-space VMMs determine the number of > get/set-able registers (via KVM_GET_ONE_REG/KVM_SET_ONE_REG) and their > register IDs. User-space VMMs use this ioctl so they don't have to > hardcode a register ID table for each architecture. In theory it is so, I only know QEMU VMM now, is there other VMMs which does not use hardcoded register ID for different architecture? Which one if there is actually. There is some potential issues by my knowledge such as: 1. How to solve the compatible issue if KVM_GET_REG_LIST does not support? 2. How to solve dependency between registers? Dependency should be solved in VMM or KVM hypervisr. Regards Bibo Mao > > I also had trouble finding information on the KVM_read_from_REG_LIST and > KVM_write_from_REG_LIST ioctl commands. As of commit > 3d29a326eba82d987a82fd59379d6d668b769965, I could not find any logic or > identifiers for these two ioctls. > > In some cases, KVM_GET_REG_LIST is a prerequisite for using > KVM_read_from_REG_LIST or KVM_write_from_REG_LIST (assuming they exist), > as you still need to know the register IDs to use these ioctls. > >> Regards >> Bibo Mao >> >>> + >>> + for (i = 0, count = 0; >>> + i < sizeof(csrs_to_save) / sizeof(csrs_to_save[0]); i++) { >>> + const u64 reg = KVM_IOC_CSRID(i); >>> + if (uindices && put_user(reg, uindices++)) >>> + return -EFAULT; >>> + count++; >>> + } >>> + >>> + /* Skip PMU CSRs if not supported by the guest */ >>> + if (!kvm_guest_has_pmu(&vcpu->arch)) >>> + return count; >>> + for (i = LOONGARCH_CSR_PERFCTRL0; i <= LOONGARCH_CSR_PERFCNTR3; >>> i++) { >>> + const u64 reg = KVM_IOC_CSRID(i); >>> + if (uindices && put_user(reg, uindices++)) >>> + return -EFAULT; >>> + count++; >>> + } >>> + >>> + return count; >>> +} >>> + >>> +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 += 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 <= 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 +1353,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; >>> >> > Thanks, > Zixing > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch 2026-02-10 3:43 ` Bibo Mao @ 2026-02-10 4:05 ` liushuyu 2026-03-09 3:52 ` liushuyu 1 sibling, 0 replies; 7+ messages in thread From: liushuyu @ 2026-02-10 4:05 UTC (permalink / raw) To: Bibo Mao, WANG Xuerui, Huacai Chen Cc: Kexy Biscuit, Mingcong Bai, Paolo Bonzini, Jonathan Corbet, Tianrui Zhao, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm, linux-doc, linux-kernel, loongarch, linux-riscv Hi Bibo, > > On 2026/2/10 上午11:23, liushuyu wrote: >> Hi Bibo, >> >>> >>> >>> On 2026/2/5 下午1:18, Zixing Liu wrote: >>>> 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@aosc.io> >>>> --- >>>> Documentation/virt/kvm/api.rst | 2 +- >>>> arch/loongarch/kvm/vcpu.c | 120 >>>> +++++++++++++++++++++++++++++++++ >>>> 2 files changed, 121 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..de02e409ae39 100644 >>>> --- a/arch/loongarch/kvm/vcpu.c >>>> +++ b/arch/loongarch/kvm/vcpu.c >>>> @@ -5,6 +5,7 @@ >>>> #include <linux/kvm_host.h> >>>> #include <asm/fpu.h> >>>> +#include <asm/kvm_host.h> >>>> #include <asm/lbt.h> >>>> #include <asm/loongarch.h> >>>> #include <asm/setup.h> >>>> @@ -14,6 +15,8 @@ >>>> #define CREATE_TRACE_POINTS >>>> #include "trace.h" >>>> +#define NUM_LBT_REGS 6 >>>> + >>>> const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { >>>> KVM_GENERIC_VCPU_STATS(), >>>> STATS_DESC_COUNTER(VCPU, int_exits), >>>> @@ -1186,6 +1189,105 @@ 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; >>>> + const unsigned int csrs_to_save[] = { >>>> + LOONGARCH_CSR_CRMD, LOONGARCH_CSR_PRMD, >>>> + LOONGARCH_CSR_EUEN, LOONGARCH_CSR_MISC, >>>> + LOONGARCH_CSR_ECFG, LOONGARCH_CSR_ESTAT, >>>> + LOONGARCH_CSR_ERA, LOONGARCH_CSR_BADV, >>>> + LOONGARCH_CSR_BADI, LOONGARCH_CSR_EENTRY, >>>> + LOONGARCH_CSR_TLBIDX, LOONGARCH_CSR_TLBEHI, >>>> + LOONGARCH_CSR_TLBELO0, LOONGARCH_CSR_TLBELO1, >>>> + LOONGARCH_CSR_ASID, LOONGARCH_CSR_PGDL, >>>> + LOONGARCH_CSR_PGDH, LOONGARCH_CSR_PGD, >>>> + LOONGARCH_CSR_PWCTL0, LOONGARCH_CSR_PWCTL1, >>>> + LOONGARCH_CSR_STLBPGSIZE, LOONGARCH_CSR_RVACFG, >>>> + LOONGARCH_CSR_CPUID, LOONGARCH_CSR_PRCFG1, >>>> + LOONGARCH_CSR_PRCFG2, LOONGARCH_CSR_PRCFG3, >>>> + LOONGARCH_CSR_KS0, LOONGARCH_CSR_KS1, >>>> + LOONGARCH_CSR_KS2, LOONGARCH_CSR_KS3, >>>> + LOONGARCH_CSR_KS4, LOONGARCH_CSR_KS5, >>>> + LOONGARCH_CSR_KS6, LOONGARCH_CSR_KS7, >>>> + LOONGARCH_CSR_TMID, LOONGARCH_CSR_CNTC, >>>> + LOONGARCH_CSR_TINTCLR, LOONGARCH_CSR_LLBCTL, >>>> + LOONGARCH_CSR_IMPCTL1, LOONGARCH_CSR_IMPCTL2, >>>> + LOONGARCH_CSR_TLBRENTRY, LOONGARCH_CSR_TLBRBADV, >>>> + LOONGARCH_CSR_TLBRERA, LOONGARCH_CSR_TLBRSAVE, >>>> + LOONGARCH_CSR_TLBRELO0, LOONGARCH_CSR_TLBRELO1, >>>> + LOONGARCH_CSR_TLBREHI, LOONGARCH_CSR_TLBRPRMD, >>>> + LOONGARCH_CSR_DMWIN0, LOONGARCH_CSR_DMWIN1, >>>> + LOONGARCH_CSR_DMWIN2, LOONGARCH_CSR_DMWIN3, >>>> + LOONGARCH_CSR_TVAL, LOONGARCH_CSR_TCFG, >>>> + }; >>> this increases much kernel stack size usage :) >>> >>> Please wait a moment, I am considering how to cleanup code about CSR >>> registers. >> Okay. >>> And KVM_GET_REG_LIST is not so urgent, else there is >>> KVM_read_from_REG_LIST/KVM_write_from_REG_LIST ioctl commands to >>> access registers in batch mode. >>> >> Adding KVM_GET_REG_LIST is not urgent. However, unlike >> KVM_read_from_REG_LIST and KVM_write_from_REG_LIST, KVM_GET_REG_LIST >> serves a different purpose. >> >> The KVM_GET_REG_LIST ioctl lets user-space VMMs determine the number of >> get/set-able registers (via KVM_GET_ONE_REG/KVM_SET_ONE_REG) and their >> register IDs. User-space VMMs use this ioctl so they don't have to >> hardcode a register ID table for each architecture. > In theory it is so, I only know QEMU VMM now, is there other VMMs > which does not use hardcoded register ID for different architecture? > Which one if there is actually. There is https://github.com/firecracker-microvm/firecracker (from Amazon), which uses https://github.com/rust-vmm/kvm as the VMM library (which uses the KVM_GET_REG_LIST ioctl to determine how many registers to save). > There is some potential issues by my knowledge such as: > 1. How to solve the compatible issue if KVM_GET_REG_LIST does not > support? I agree this could be an issue for LoongArch as we are trying to add this ioctl very late. I am guessing we either tell the user that you will need to use Linux 7.1 or something for this to work; or, for older kernel versions, we have to resort to embedding a table in the user-space VMM (and maybe remove it after a few years). For other architectures, they implemented it somewhat early and did not have this issue. > 2. How to solve dependency between registers? Dependency should be > solved in VMM or KVM hypervisr. If the dependency issue can be solved by simply re-ordering the register IDs in the list returned to the user space, we can help the user space VMM by sorting the list to the correct order when the kernel-side is walking the CSR list (for instance, put the registers that require other registers to be saved last). If that is not the case, we will need to add a paragraph to the KVM documentation explaining how to properly interpret the list returned by this ioctl. > > Regards > Bibo Mao >> >> I also had trouble finding information on the KVM_read_from_REG_LIST and >> KVM_write_from_REG_LIST ioctl commands. As of commit >> 3d29a326eba82d987a82fd59379d6d668b769965, I could not find any logic or >> identifiers for these two ioctls. >> >> In some cases, KVM_GET_REG_LIST is a prerequisite for using >> KVM_read_from_REG_LIST or KVM_write_from_REG_LIST (assuming they exist), >> as you still need to know the register IDs to use these ioctls. >> >>> Regards >>> Bibo Mao >>> >>>> + >>>> + for (i = 0, count = 0; >>>> + i < sizeof(csrs_to_save) / sizeof(csrs_to_save[0]); i++) { >>>> + const u64 reg = KVM_IOC_CSRID(i); >>>> + if (uindices && put_user(reg, uindices++)) >>>> + return -EFAULT; >>>> + count++; >>>> + } >>>> + >>>> + /* Skip PMU CSRs if not supported by the guest */ >>>> + if (!kvm_guest_has_pmu(&vcpu->arch)) >>>> + return count; >>>> + for (i = LOONGARCH_CSR_PERFCTRL0; i <= LOONGARCH_CSR_PERFCNTR3; >>>> i++) { >>>> + const u64 reg = KVM_IOC_CSRID(i); >>>> + if (uindices && put_user(reg, uindices++)) >>>> + return -EFAULT; >>>> + count++; >>>> + } >>>> + >>>> + return count; >>>> +} >>>> + >>>> +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 += 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 <= 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 +1353,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; >>>> >>> >> Thanks, >> Zixing >> > Thanks, Zixing ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch 2026-02-10 3:43 ` Bibo Mao 2026-02-10 4:05 ` liushuyu @ 2026-03-09 3:52 ` liushuyu 2026-03-09 6:30 ` Bibo Mao 1 sibling, 1 reply; 7+ messages in thread From: liushuyu @ 2026-03-09 3:52 UTC (permalink / raw) To: Bibo Mao, WANG Xuerui, Huacai Chen Cc: Kexy Biscuit, Mingcong Bai, Paolo Bonzini, Jonathan Corbet, Tianrui Zhao, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm, linux-doc, linux-kernel, loongarch, linux-riscv Hi Bibo, It seems like my last email might have got bounced or landed in your spam filter. So this email is a re-send of the last one. > On 2026/2/10 上午11:23, liushuyu wrote: >> Hi Bibo, >> >>> >>> On 2026/2/5 下午1:18, Zixing Liu wrote: >>>> 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@aosc.io> >>>> --- >>>> Documentation/virt/kvm/api.rst | 2 +- >>>> arch/loongarch/kvm/vcpu.c | 120 >>>> +++++++++++++++++++++++++++++++++ >>>> 2 files changed, 121 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..de02e409ae39 100644 >>>> --- a/arch/loongarch/kvm/vcpu.c >>>> +++ b/arch/loongarch/kvm/vcpu.c >>>> @@ -5,6 +5,7 @@ >>>> #include <linux/kvm_host.h> >>>> #include <asm/fpu.h> >>>> +#include <asm/kvm_host.h> >>>> #include <asm/lbt.h> >>>> #include <asm/loongarch.h> >>>> #include <asm/setup.h> >>>> @@ -14,6 +15,8 @@ >>>> #define CREATE_TRACE_POINTS >>>> #include "trace.h" >>>> +#define NUM_LBT_REGS 6 >>>> + >>>> const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { >>>> KVM_GENERIC_VCPU_STATS(), >>>> STATS_DESC_COUNTER(VCPU, int_exits), >>>> @@ -1186,6 +1189,105 @@ 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; >>>> + const unsigned int csrs_to_save[] = { >>>> + LOONGARCH_CSR_CRMD, LOONGARCH_CSR_PRMD, >>>> + LOONGARCH_CSR_EUEN, LOONGARCH_CSR_MISC, >>>> + LOONGARCH_CSR_ECFG, LOONGARCH_CSR_ESTAT, >>>> + LOONGARCH_CSR_ERA, LOONGARCH_CSR_BADV, >>>> + LOONGARCH_CSR_BADI, LOONGARCH_CSR_EENTRY, >>>> + LOONGARCH_CSR_TLBIDX, LOONGARCH_CSR_TLBEHI, >>>> + LOONGARCH_CSR_TLBELO0, LOONGARCH_CSR_TLBELO1, >>>> + LOONGARCH_CSR_ASID, LOONGARCH_CSR_PGDL, >>>> + LOONGARCH_CSR_PGDH, LOONGARCH_CSR_PGD, >>>> + LOONGARCH_CSR_PWCTL0, LOONGARCH_CSR_PWCTL1, >>>> + LOONGARCH_CSR_STLBPGSIZE, LOONGARCH_CSR_RVACFG, >>>> + LOONGARCH_CSR_CPUID, LOONGARCH_CSR_PRCFG1, >>>> + LOONGARCH_CSR_PRCFG2, LOONGARCH_CSR_PRCFG3, >>>> + LOONGARCH_CSR_KS0, LOONGARCH_CSR_KS1, >>>> + LOONGARCH_CSR_KS2, LOONGARCH_CSR_KS3, >>>> + LOONGARCH_CSR_KS4, LOONGARCH_CSR_KS5, >>>> + LOONGARCH_CSR_KS6, LOONGARCH_CSR_KS7, >>>> + LOONGARCH_CSR_TMID, LOONGARCH_CSR_CNTC, >>>> + LOONGARCH_CSR_TINTCLR, LOONGARCH_CSR_LLBCTL, >>>> + LOONGARCH_CSR_IMPCTL1, LOONGARCH_CSR_IMPCTL2, >>>> + LOONGARCH_CSR_TLBRENTRY, LOONGARCH_CSR_TLBRBADV, >>>> + LOONGARCH_CSR_TLBRERA, LOONGARCH_CSR_TLBRSAVE, >>>> + LOONGARCH_CSR_TLBRELO0, LOONGARCH_CSR_TLBRELO1, >>>> + LOONGARCH_CSR_TLBREHI, LOONGARCH_CSR_TLBRPRMD, >>>> + LOONGARCH_CSR_DMWIN0, LOONGARCH_CSR_DMWIN1, >>>> + LOONGARCH_CSR_DMWIN2, LOONGARCH_CSR_DMWIN3, >>>> + LOONGARCH_CSR_TVAL, LOONGARCH_CSR_TCFG, >>>> + }; >>> this increases much kernel stack size usage :) >>> >>> Please wait a moment, I am considering how to cleanup code about CSR >>> registers. >> Okay. I am also very interested in how this CSR register logic clean-up would work. Can you share some details regarding this clean-up? >>> And KVM_GET_REG_LIST is not so urgent, else there is >>> KVM_read_from_REG_LIST/KVM_write_from_REG_LIST ioctl commands to >>> access registers in batch mode. >>> >> Adding KVM_GET_REG_LIST is not urgent. However, unlike >> KVM_read_from_REG_LIST and KVM_write_from_REG_LIST, KVM_GET_REG_LIST >> serves a different purpose. >> >> The KVM_GET_REG_LIST ioctl lets user-space VMMs determine the number of >> get/set-able registers (via KVM_GET_ONE_REG/KVM_SET_ONE_REG) and their >> register IDs. User-space VMMs use this ioctl so they don't have to >> hardcode a register ID table for each architecture. > In theory it is so, I only know QEMU VMM now, is there other VMMs > which does not use hardcoded register ID for different architecture? > Which one if there is actually. There is https://github.com/firecracker-microvm/firecracker (from Amazon), which uses https://github.com/rust-vmm/kvm as the VMM library (which uses the KVM_GET_REG_LIST ioctl to determine how many registers to save). > There is some potential issues by my knowledge such as: > 1. How to solve the compatible issue if KVM_GET_REG_LIST does not > support? I agree this could be an issue for LoongArch as we are trying to add this ioctl very late. I am guessing we either tell the user that you will need to use Linux 7.1 or something for this to work; or, for older kernel versions, we have to resort to embedding a table in the user-space VMM (and maybe remove it after a few years). For other architectures, they implemented it somewhat early and did not have this issue. > 2. How to solve dependency between registers? Dependency should be > solved in VMM or KVM hypervisr. If the dependency issue can be solved by simply re-ordering the register IDs in the list returned to the user space, we can help the user space VMM by sorting the list to the correct order when the kernel-side is walking the CSR list (for instance, put the registers that require other registers to be saved last). If that is not the case, we will need to add a paragraph to the KVM documentation explaining how to properly interpret the list returned by this ioctl. > Regards > Bibo Mao >> I also had trouble finding information on the KVM_read_from_REG_LIST and >> KVM_write_from_REG_LIST ioctl commands. As of commit >> 3d29a326eba82d987a82fd59379d6d668b769965, I could not find any logic or >> identifiers for these two ioctls. >> >> In some cases, KVM_GET_REG_LIST is a prerequisite for using >> KVM_read_from_REG_LIST or KVM_write_from_REG_LIST (assuming they exist), >> as you still need to know the register IDs to use these ioctls. >> >>> Regards >>> Bibo Mao >>> >>>> + >>>> + for (i = 0, count = 0; >>>> + i < sizeof(csrs_to_save) / sizeof(csrs_to_save[0]); i++) { >>>> + const u64 reg = KVM_IOC_CSRID(i); >>>> + if (uindices && put_user(reg, uindices++)) >>>> + return -EFAULT; >>>> + count++; >>>> + } >>>> + >>>> + /* Skip PMU CSRs if not supported by the guest */ >>>> + if (!kvm_guest_has_pmu(&vcpu->arch)) >>>> + return count; >>>> + for (i = LOONGARCH_CSR_PERFCTRL0; i <= LOONGARCH_CSR_PERFCNTR3; >>>> i++) { >>>> + const u64 reg = KVM_IOC_CSRID(i); >>>> + if (uindices && put_user(reg, uindices++)) >>>> + return -EFAULT; >>>> + count++; >>>> + } >>>> + >>>> + return count; >>>> +} >>>> + >>>> +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 += 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 <= 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 +1353,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; >>>> >>> >> Thanks, >> Zixing >> > Thanks, Zixing ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch 2026-03-09 3:52 ` liushuyu @ 2026-03-09 6:30 ` Bibo Mao 0 siblings, 0 replies; 7+ messages in thread From: Bibo Mao @ 2026-03-09 6:30 UTC (permalink / raw) To: liushuyu, WANG Xuerui, Huacai Chen Cc: Kexy Biscuit, Mingcong Bai, Paolo Bonzini, Jonathan Corbet, Tianrui Zhao, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm, linux-doc, linux-kernel, loongarch, linux-riscv On 2026/3/9 上午11:52, liushuyu wrote: > Hi Bibo, > > It seems like my last email might have got bounced or landed in your > spam filter. > > So this email is a re-send of the last one. > >> On 2026/2/10 上午11:23, liushuyu wrote: >>> Hi Bibo, >>> >>>> >>>> On 2026/2/5 下午1:18, Zixing Liu wrote: >>>>> 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@aosc.io> >>>>> --- >>>>> Documentation/virt/kvm/api.rst | 2 +- >>>>> arch/loongarch/kvm/vcpu.c | 120 >>>>> +++++++++++++++++++++++++++++++++ >>>>> 2 files changed, 121 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..de02e409ae39 100644 >>>>> --- a/arch/loongarch/kvm/vcpu.c >>>>> +++ b/arch/loongarch/kvm/vcpu.c >>>>> @@ -5,6 +5,7 @@ >>>>> #include <linux/kvm_host.h> >>>>> #include <asm/fpu.h> >>>>> +#include <asm/kvm_host.h> >>>>> #include <asm/lbt.h> >>>>> #include <asm/loongarch.h> >>>>> #include <asm/setup.h> >>>>> @@ -14,6 +15,8 @@ >>>>> #define CREATE_TRACE_POINTS >>>>> #include "trace.h" >>>>> +#define NUM_LBT_REGS 6 >>>>> + >>>>> const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { >>>>> KVM_GENERIC_VCPU_STATS(), >>>>> STATS_DESC_COUNTER(VCPU, int_exits), >>>>> @@ -1186,6 +1189,105 @@ 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; >>>>> + const unsigned int csrs_to_save[] = { >>>>> + LOONGARCH_CSR_CRMD, LOONGARCH_CSR_PRMD, >>>>> + LOONGARCH_CSR_EUEN, LOONGARCH_CSR_MISC, >>>>> + LOONGARCH_CSR_ECFG, LOONGARCH_CSR_ESTAT, >>>>> + LOONGARCH_CSR_ERA, LOONGARCH_CSR_BADV, >>>>> + LOONGARCH_CSR_BADI, LOONGARCH_CSR_EENTRY, >>>>> + LOONGARCH_CSR_TLBIDX, LOONGARCH_CSR_TLBEHI, >>>>> + LOONGARCH_CSR_TLBELO0, LOONGARCH_CSR_TLBELO1, >>>>> + LOONGARCH_CSR_ASID, LOONGARCH_CSR_PGDL, >>>>> + LOONGARCH_CSR_PGDH, LOONGARCH_CSR_PGD, >>>>> + LOONGARCH_CSR_PWCTL0, LOONGARCH_CSR_PWCTL1, >>>>> + LOONGARCH_CSR_STLBPGSIZE, LOONGARCH_CSR_RVACFG, >>>>> + LOONGARCH_CSR_CPUID, LOONGARCH_CSR_PRCFG1, >>>>> + LOONGARCH_CSR_PRCFG2, LOONGARCH_CSR_PRCFG3, >>>>> + LOONGARCH_CSR_KS0, LOONGARCH_CSR_KS1, >>>>> + LOONGARCH_CSR_KS2, LOONGARCH_CSR_KS3, >>>>> + LOONGARCH_CSR_KS4, LOONGARCH_CSR_KS5, >>>>> + LOONGARCH_CSR_KS6, LOONGARCH_CSR_KS7, >>>>> + LOONGARCH_CSR_TMID, LOONGARCH_CSR_CNTC, >>>>> + LOONGARCH_CSR_TINTCLR, LOONGARCH_CSR_LLBCTL, >>>>> + LOONGARCH_CSR_IMPCTL1, LOONGARCH_CSR_IMPCTL2, >>>>> + LOONGARCH_CSR_TLBRENTRY, LOONGARCH_CSR_TLBRBADV, >>>>> + LOONGARCH_CSR_TLBRERA, LOONGARCH_CSR_TLBRSAVE, >>>>> + LOONGARCH_CSR_TLBRELO0, LOONGARCH_CSR_TLBRELO1, >>>>> + LOONGARCH_CSR_TLBREHI, LOONGARCH_CSR_TLBRPRMD, >>>>> + LOONGARCH_CSR_DMWIN0, LOONGARCH_CSR_DMWIN1, >>>>> + LOONGARCH_CSR_DMWIN2, LOONGARCH_CSR_DMWIN3, >>>>> + LOONGARCH_CSR_TVAL, LOONGARCH_CSR_TCFG, >>>>> + }; >>>> this increases much kernel stack size usage :) >>>> >>>> Please wait a moment, I am considering how to cleanup code about CSR >>>> registers. >>> Okay. > > I am also very interested in how this CSR register logic clean-up would > work. > > Can you share some details regarding this clean-up? > There are some pending issues unsolved, such as _kvm_getcsr() with id == LOONGARCH_CSR_ESTAT case. It is obvious improper to add vcpu_load()/vcpu_put() here with get_csr() register. >>>> And KVM_GET_REG_LIST is not so urgent, else there is >>>> KVM_read_from_REG_LIST/KVM_write_from_REG_LIST ioctl commands to >>>> access registers in batch mode. >>>> >>> Adding KVM_GET_REG_LIST is not urgent. However, unlike >>> KVM_read_from_REG_LIST and KVM_write_from_REG_LIST, KVM_GET_REG_LIST >>> serves a different purpose. >>> >>> The KVM_GET_REG_LIST ioctl lets user-space VMMs determine the number of >>> get/set-able registers (via KVM_GET_ONE_REG/KVM_SET_ONE_REG) and their >>> register IDs. User-space VMMs use this ioctl so they don't have to >>> hardcode a register ID table for each architecture. >> In theory it is so, I only know QEMU VMM now, is there other VMMs >> which does not use hardcoded register ID for different architecture? >> Which one if there is actually. > There is https://github.com/firecracker-microvm/firecracker (from > Amazon), which uses https://github.com/rust-vmm/kvm as the VMM library > (which uses the KVM_GET_REG_LIST ioctl to determine how many registers > to save). >> There is some potential issues by my knowledge such as: >> 1. How to solve the compatible issue if KVM_GET_REG_LIST does not >> support? > I agree this could be an issue for LoongArch as we are trying to add > this ioctl very late. I am guessing we either tell the user that you > will need to use Linux 7.1 or something for this to work; or, for older > kernel versions, we have to resort to embedding a table in the > user-space VMM (and maybe remove it after a few years). For other > architectures, they implemented it somewhat early and did not have this > issue. I agree with this, the compatible issue only can be solved with time pass away until old kernel is not supported. >> 2. How to solve dependency between registers? Dependency should be >> solved in VMM or KVM hypervisr. > If the dependency issue can be solved by simply re-ordering the register > IDs in the list returned to the user space, we can help the user space > VMM by sorting the list to the correct order when the kernel-side is > walking the CSR list (for instance, put the registers that require other > registers to be saved last). If that is not the case, we will need to > add a paragraph to the KVM documentation explaining how to properly > interpret the list returned by this ioctl. There may be different dependency issues regarding read access and write access, do you agree that? How to solve it. The important thing is that I think this requirement is not urgent and old method can work. The new API is not so matured and also it will bring unexpected compatible issue. So I suggest that it need more time. Maybe you think that it is important. I have such experience also, every time when I submit one patch, I think it is important. Indeed without the patch or the patch is submit after months, the world still works well :) Regards Bibo Mao >> Regards >> Bibo Mao >>> I also had trouble finding information on the KVM_read_from_REG_LIST and >>> KVM_write_from_REG_LIST ioctl commands. As of commit >>> 3d29a326eba82d987a82fd59379d6d668b769965, I could not find any logic or >>> identifiers for these two ioctls. >>> >>> In some cases, KVM_GET_REG_LIST is a prerequisite for using >>> KVM_read_from_REG_LIST or KVM_write_from_REG_LIST (assuming they exist), >>> as you still need to know the register IDs to use these ioctls. >>> >>>> Regards >>>> Bibo Mao >>>> >>>>> + >>>>> + for (i = 0, count = 0; >>>>> + i < sizeof(csrs_to_save) / sizeof(csrs_to_save[0]); i++) { >>>>> + const u64 reg = KVM_IOC_CSRID(i); >>>>> + if (uindices && put_user(reg, uindices++)) >>>>> + return -EFAULT; >>>>> + count++; >>>>> + } >>>>> + >>>>> + /* Skip PMU CSRs if not supported by the guest */ >>>>> + if (!kvm_guest_has_pmu(&vcpu->arch)) >>>>> + return count; >>>>> + for (i = LOONGARCH_CSR_PERFCTRL0; i <= LOONGARCH_CSR_PERFCNTR3; >>>>> i++) { >>>>> + const u64 reg = KVM_IOC_CSRID(i); >>>>> + if (uindices && put_user(reg, uindices++)) >>>>> + return -EFAULT; >>>>> + count++; >>>>> + } >>>>> + >>>>> + return count; >>>>> +} >>>>> + >>>>> +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 += 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 <= 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 +1353,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; >>>>> >>>> >>> Thanks, >>> Zixing >>> >> > Thanks, > Zixing > ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-03-09 6:33 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-02-05 5:18 [PATCH v5] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch Zixing Liu 2026-02-10 2:42 ` Bibo Mao 2026-02-10 3:23 ` liushuyu 2026-02-10 3:43 ` Bibo Mao 2026-02-10 4:05 ` liushuyu 2026-03-09 3:52 ` liushuyu 2026-03-09 6:30 ` Bibo Mao
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®