[PATCH v3] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch
liushuyu
liushuyu at aosc.io
Sun Feb 1 18:41:05 PST 2026
>
>
> On 2026/2/1 下午3:21, 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 at aosc.io>
>> ---
>> Documentation/virt/kvm/api.rst | 2 +-
>> arch/loongarch/kvm/vcpu.c | 81 ++++++++++++++++++++++++++++++++++
>> 2 files changed, 82 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..fb8001deadc9 100644
>> --- a/arch/loongarch/kvm/vcpu.c
>> +++ b/arch/loongarch/kvm/vcpu.c
>> @@ -14,6 +14,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 +1188,67 @@ 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)))
> My main concern is how to use KVM_GET_REG_LIST ioctl command, there
> will be compatible issue if the detail use scenery about
> KVM_GET_REG_LIST command is not clear.
>
> Can KVM_GET_REG_LIST ioctl command be used before vCPU feature
> finalized? If not, it is only used after vCPU feature finalized, guest
> CSR registers should base on vCPU features rather than host features.
> Here get_gcsr_flag() is based on host features.
>
We can add a warning to the documentation saying using KVM_GET_REG_LIST
before vCPU feature finalization is forbidden. This is how ARM
implemented their thing (the documentation said "Other calls that depend
on a particular feature being finalized, such as KVM_RUN,
KVM_GET_REG_LIST, KVM_GET_ONE_REG and KVM_SET_ONE_REG, will fail with
-EPERM unless the feature has already been finalized by means of a
KVM_ARM_VCPU_FINALIZE call.") We can probably do the same.
What do you think? If you think this is acceptable, I can send a v4
patch that adds a similar warning to the documentation.
> Regards
> Bibo Mao
Thanks,
Zixing
>> + 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_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 +1314,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;
>>
>
More information about the linux-riscv
mailing list