aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kvm/mips.c
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2014-12-02 10:48:24 -0500
committerJames Hogan <james.hogan@imgtec.com>2015-03-27 17:25:21 -0400
commitab86bd600400357ffa0dfdb1797f587476d01352 (patch)
tree265d24436dc03ac0e1ff2fa3a1652feb3346b6ff /arch/mips/kvm/mips.c
parentc2537ed9fb8e17d713e5e67fcede047699d25814 (diff)
MIPS: KVM: Expose MSA registers
Add KVM register numbers for the MIPS SIMD Architecture (MSA) registers, and implement access to them with the KVM_GET_ONE_REG / KVM_SET_ONE_REG ioctls when the MSA capability is enabled (exposed in a later patch) and present in the guest according to its Config3.MSAP bit. The MSA vector registers use the same register numbers as the FPU registers except with a different size (128bits). Since MSA depends on Status.FR=1, these registers are inaccessible when Status.FR=0. These registers are returned as a single native endian 128bit value, rather than least significant half first with each 64-bit half native endian as the kernel uses internally. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: Gleb Natapov <gleb@kernel.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: linux-api@vger.kernel.org Cc: linux-doc@vger.kernel.org
Diffstat (limited to 'arch/mips/kvm/mips.c')
-rw-r--r--arch/mips/kvm/mips.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index e02c7e5a12ff..35d3146895f1 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -531,6 +531,7 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
531 struct mips_fpu_struct *fpu = &vcpu->arch.fpu; 531 struct mips_fpu_struct *fpu = &vcpu->arch.fpu;
532 int ret; 532 int ret;
533 s64 v; 533 s64 v;
534 s64 vs[2];
534 unsigned int idx; 535 unsigned int idx;
535 536
536 switch (reg->id) { 537 switch (reg->id) {
@@ -579,6 +580,35 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
579 v = fpu->fcr31; 580 v = fpu->fcr31;
580 break; 581 break;
581 582
583 /* MIPS SIMD Architecture (MSA) registers */
584 case KVM_REG_MIPS_VEC_128(0) ... KVM_REG_MIPS_VEC_128(31):
585 if (!kvm_mips_guest_has_msa(&vcpu->arch))
586 return -EINVAL;
587 /* Can't access MSA registers in FR=0 mode */
588 if (!(kvm_read_c0_guest_status(cop0) & ST0_FR))
589 return -EINVAL;
590 idx = reg->id - KVM_REG_MIPS_VEC_128(0);
591#ifdef CONFIG_CPU_LITTLE_ENDIAN
592 /* least significant byte first */
593 vs[0] = get_fpr64(&fpu->fpr[idx], 0);
594 vs[1] = get_fpr64(&fpu->fpr[idx], 1);
595#else
596 /* most significant byte first */
597 vs[0] = get_fpr64(&fpu->fpr[idx], 1);
598 vs[1] = get_fpr64(&fpu->fpr[idx], 0);
599#endif
600 break;
601 case KVM_REG_MIPS_MSA_IR:
602 if (!kvm_mips_guest_has_msa(&vcpu->arch))
603 return -EINVAL;
604 v = boot_cpu_data.msa_id;
605 break;
606 case KVM_REG_MIPS_MSA_CSR:
607 if (!kvm_mips_guest_has_msa(&vcpu->arch))
608 return -EINVAL;
609 v = fpu->msacsr;
610 break;
611
582 /* Co-processor 0 registers */ 612 /* Co-processor 0 registers */
583 case KVM_REG_MIPS_CP0_INDEX: 613 case KVM_REG_MIPS_CP0_INDEX:
584 v = (long)kvm_read_c0_guest_index(cop0); 614 v = (long)kvm_read_c0_guest_index(cop0);
@@ -664,6 +694,10 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
664 u32 v32 = (u32)v; 694 u32 v32 = (u32)v;
665 695
666 return put_user(v32, uaddr32); 696 return put_user(v32, uaddr32);
697 } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) {
698 void __user *uaddr = (void __user *)(long)reg->addr;
699
700 return copy_to_user(uaddr, vs, 16);
667 } else { 701 } else {
668 return -EINVAL; 702 return -EINVAL;
669 } 703 }
@@ -675,6 +709,7 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
675 struct mips_coproc *cop0 = vcpu->arch.cop0; 709 struct mips_coproc *cop0 = vcpu->arch.cop0;
676 struct mips_fpu_struct *fpu = &vcpu->arch.fpu; 710 struct mips_fpu_struct *fpu = &vcpu->arch.fpu;
677 s64 v; 711 s64 v;
712 s64 vs[2];
678 unsigned int idx; 713 unsigned int idx;
679 714
680 if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) { 715 if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) {
@@ -689,6 +724,10 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
689 if (get_user(v32, uaddr32) != 0) 724 if (get_user(v32, uaddr32) != 0)
690 return -EFAULT; 725 return -EFAULT;
691 v = (s64)v32; 726 v = (s64)v32;
727 } else if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U128) {
728 void __user *uaddr = (void __user *)(long)reg->addr;
729
730 return copy_from_user(vs, uaddr, 16);
692 } else { 731 } else {
693 return -EINVAL; 732 return -EINVAL;
694 } 733 }
@@ -742,6 +781,32 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
742 fpu->fcr31 = v; 781 fpu->fcr31 = v;
743 break; 782 break;
744 783
784 /* MIPS SIMD Architecture (MSA) registers */
785 case KVM_REG_MIPS_VEC_128(0) ... KVM_REG_MIPS_VEC_128(31):
786 if (!kvm_mips_guest_has_msa(&vcpu->arch))
787 return -EINVAL;
788 idx = reg->id - KVM_REG_MIPS_VEC_128(0);
789#ifdef CONFIG_CPU_LITTLE_ENDIAN
790 /* least significant byte first */
791 set_fpr64(&fpu->fpr[idx], 0, vs[0]);
792 set_fpr64(&fpu->fpr[idx], 1, vs[1]);
793#else
794 /* most significant byte first */
795 set_fpr64(&fpu->fpr[idx], 1, vs[0]);
796 set_fpr64(&fpu->fpr[idx], 0, vs[1]);
797#endif
798 break;
799 case KVM_REG_MIPS_MSA_IR:
800 if (!kvm_mips_guest_has_msa(&vcpu->arch))
801 return -EINVAL;
802 /* Read-only */
803 break;
804 case KVM_REG_MIPS_MSA_CSR:
805 if (!kvm_mips_guest_has_msa(&vcpu->arch))
806 return -EINVAL;
807 fpu->msacsr = v;
808 break;
809
745 /* Co-processor 0 registers */ 810 /* Co-processor 0 registers */
746 case KVM_REG_MIPS_CP0_INDEX: 811 case KVM_REG_MIPS_CP0_INDEX:
747 kvm_write_c0_guest_index(cop0, v); 812 kvm_write_c0_guest_index(cop0, v);