[PATCH v3] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch

Bibo Mao maobibo at loongson.cn
Sun Feb 1 18:59:01 PST 2026



On 2026/2/2 上午10:41, liushuyu wrote:
> 
>>
>>
>> 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.
No special document is need.

If KVM_GET_REG_LIST command is used after vCPU feature finalization, 
vCPU feature can be checked when KVM_GET_REG_LIST command is called.

Here funciton kvm_loongarch_walk_csrs() should be modified. 
get_gcsr_flag() is based on host HW feature rather than vCPU feature. 
For example VM can disable PMU/MSGINT features, so CSR registers 
relative with PMU/MSGINT should be listed based on vCPU features.

Regards
Bibo Mao
> 
>> 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(&reg_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, &reg_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