[PATCH v3] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch

Zixing Liu posted 1 patch 5 days, 23 hours ago
There is a newer version of this series
Documentation/virt/kvm/api.rst |  2 +-
arch/loongarch/kvm/vcpu.c      | 81 ++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+), 1 deletion(-)
[PATCH v3] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch
Posted by Zixing Liu 5 days, 23 hours ago
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      | 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)))
+			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;
-- 
2.52.0
Re: [PATCH v3] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch
Posted by Bibo Mao 5 days, 4 hours ago

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@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.

Regards
Bibo Mao
> +			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;
> 

Re: [PATCH v3] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch
Posted by liushuyu 5 days, 4 hours ago
>
>
> 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@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(&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;
>>
>
Re: [PATCH v3] KVM: Add KVM_GET_REG_LIST ioctl for LoongArch
Posted by Bibo Mao 5 days, 4 hours ago

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@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;
>>>
>>