Browse Source

MIPS: KVM: List FPU/MSA registers

Make KVM_GET_REG_LIST list FPU & MSA registers. Specifically we list all
32 vector registers when MSA can be enabled, 32 single-precision FP
registers when FPU can be enabled, and either 16 or 32 double-precision
FP registers when FPU can be enabled depending on whether FR mode is
supported (which provides 32 doubles instead of 16 even doubles).

Note, these registers may still be inaccessible depending on the current
FP mode of the guest.

Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: kvm@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
James Hogan 9 năm trước cách đây
mục cha
commit
e57759306c
1 tập tin đã thay đổi với 58 bổ sung0 xóa
  1. 58 0
      arch/mips/kvm/mips.c

+ 58 - 0
arch/mips/kvm/mips.c

@@ -538,11 +538,29 @@ static u64 kvm_mips_get_one_regs[] = {
 	KVM_REG_MIPS_COUNT_HZ,
 	KVM_REG_MIPS_COUNT_HZ,
 };
 };
 
 
+static u64 kvm_mips_get_one_regs_fpu[] = {
+	KVM_REG_MIPS_FCR_IR,
+	KVM_REG_MIPS_FCR_CSR,
+};
+
+static u64 kvm_mips_get_one_regs_msa[] = {
+	KVM_REG_MIPS_MSA_IR,
+	KVM_REG_MIPS_MSA_CSR,
+};
+
 static unsigned long kvm_mips_num_regs(struct kvm_vcpu *vcpu)
 static unsigned long kvm_mips_num_regs(struct kvm_vcpu *vcpu)
 {
 {
 	unsigned long ret;
 	unsigned long ret;
 
 
 	ret = ARRAY_SIZE(kvm_mips_get_one_regs);
 	ret = ARRAY_SIZE(kvm_mips_get_one_regs);
+	if (kvm_mips_guest_can_have_fpu(&vcpu->arch)) {
+		ret += ARRAY_SIZE(kvm_mips_get_one_regs_fpu) + 48;
+		/* odd doubles */
+		if (boot_cpu_data.fpu_id & MIPS_FPIR_F64)
+			ret += 16;
+	}
+	if (kvm_mips_guest_can_have_msa(&vcpu->arch))
+		ret += ARRAY_SIZE(kvm_mips_get_one_regs_msa) + 32;
 	ret += kvm_mips_callbacks->num_regs(vcpu);
 	ret += kvm_mips_callbacks->num_regs(vcpu);
 
 
 	return ret;
 	return ret;
@@ -550,11 +568,51 @@ static unsigned long kvm_mips_num_regs(struct kvm_vcpu *vcpu)
 
 
 static int kvm_mips_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices)
 static int kvm_mips_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices)
 {
 {
+	u64 index;
+	unsigned int i;
+
 	if (copy_to_user(indices, kvm_mips_get_one_regs,
 	if (copy_to_user(indices, kvm_mips_get_one_regs,
 			 sizeof(kvm_mips_get_one_regs)))
 			 sizeof(kvm_mips_get_one_regs)))
 		return -EFAULT;
 		return -EFAULT;
 	indices += ARRAY_SIZE(kvm_mips_get_one_regs);
 	indices += ARRAY_SIZE(kvm_mips_get_one_regs);
 
 
+	if (kvm_mips_guest_can_have_fpu(&vcpu->arch)) {
+		if (copy_to_user(indices, kvm_mips_get_one_regs_fpu,
+				 sizeof(kvm_mips_get_one_regs_fpu)))
+			return -EFAULT;
+		indices += ARRAY_SIZE(kvm_mips_get_one_regs_fpu);
+
+		for (i = 0; i < 32; ++i) {
+			index = KVM_REG_MIPS_FPR_32(i);
+			if (copy_to_user(indices, &index, sizeof(index)))
+				return -EFAULT;
+			++indices;
+
+			/* skip odd doubles if no F64 */
+			if (i & 1 && !(boot_cpu_data.fpu_id & MIPS_FPIR_F64))
+				continue;
+
+			index = KVM_REG_MIPS_FPR_64(i);
+			if (copy_to_user(indices, &index, sizeof(index)))
+				return -EFAULT;
+			++indices;
+		}
+	}
+
+	if (kvm_mips_guest_can_have_msa(&vcpu->arch)) {
+		if (copy_to_user(indices, kvm_mips_get_one_regs_msa,
+				 sizeof(kvm_mips_get_one_regs_msa)))
+			return -EFAULT;
+		indices += ARRAY_SIZE(kvm_mips_get_one_regs_msa);
+
+		for (i = 0; i < 32; ++i) {
+			index = KVM_REG_MIPS_VEC_128(i);
+			if (copy_to_user(indices, &index, sizeof(index)))
+				return -EFAULT;
+			++indices;
+		}
+	}
+
 	return kvm_mips_callbacks->copy_reg_indices(vcpu, indices);
 	return kvm_mips_callbacks->copy_reg_indices(vcpu, indices);
 }
 }