aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kvm
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:17 -0400
commit379245cdf1d1efc1eccc38bf0cc985dae232123d (patch)
tree6b61c5f80129fac86533f2e7cc3d05e8320324b8 /arch/mips/kvm
parent1c0cd66adbac8aa339b9521eceb18b00d1b0699e (diff)
MIPS: KVM: Expose FPU registers
Add KVM register numbers for the MIPS FPU registers, and implement access to them with the KVM_GET_ONE_REG / KVM_SET_ONE_REG ioctls when the FPU capability is enabled (exposed in a later patch) and present in the guest according to its Config1.FP bit. The registers are accessible in the current mode of the guest, with each sized access showing what the guest would see with an equivalent access, and like the architecture they may become UNPREDICTABLE if the FR mode is changed. When FR=0, odd doubles are inaccessible as they do not exist in that mode. Signed-off-by: James Hogan <james.hogan@imgtec.com> Acked-by: 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')
-rw-r--r--arch/mips/kvm/mips.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index dd0833833bea..5e41afe15ae8 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -526,10 +526,13 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
526 const struct kvm_one_reg *reg) 526 const struct kvm_one_reg *reg)
527{ 527{
528 struct mips_coproc *cop0 = vcpu->arch.cop0; 528 struct mips_coproc *cop0 = vcpu->arch.cop0;
529 struct mips_fpu_struct *fpu = &vcpu->arch.fpu;
529 int ret; 530 int ret;
530 s64 v; 531 s64 v;
532 unsigned int idx;
531 533
532 switch (reg->id) { 534 switch (reg->id) {
535 /* General purpose registers */
533 case KVM_REG_MIPS_R0 ... KVM_REG_MIPS_R31: 536 case KVM_REG_MIPS_R0 ... KVM_REG_MIPS_R31:
534 v = (long)vcpu->arch.gprs[reg->id - KVM_REG_MIPS_R0]; 537 v = (long)vcpu->arch.gprs[reg->id - KVM_REG_MIPS_R0];
535 break; 538 break;
@@ -543,6 +546,38 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
543 v = (long)vcpu->arch.pc; 546 v = (long)vcpu->arch.pc;
544 break; 547 break;
545 548
549 /* Floating point registers */
550 case KVM_REG_MIPS_FPR_32(0) ... KVM_REG_MIPS_FPR_32(31):
551 if (!kvm_mips_guest_has_fpu(&vcpu->arch))
552 return -EINVAL;
553 idx = reg->id - KVM_REG_MIPS_FPR_32(0);
554 /* Odd singles in top of even double when FR=0 */
555 if (kvm_read_c0_guest_status(cop0) & ST0_FR)
556 v = get_fpr32(&fpu->fpr[idx], 0);
557 else
558 v = get_fpr32(&fpu->fpr[idx & ~1], idx & 1);
559 break;
560 case KVM_REG_MIPS_FPR_64(0) ... KVM_REG_MIPS_FPR_64(31):
561 if (!kvm_mips_guest_has_fpu(&vcpu->arch))
562 return -EINVAL;
563 idx = reg->id - KVM_REG_MIPS_FPR_64(0);
564 /* Can't access odd doubles in FR=0 mode */
565 if (idx & 1 && !(kvm_read_c0_guest_status(cop0) & ST0_FR))
566 return -EINVAL;
567 v = get_fpr64(&fpu->fpr[idx], 0);
568 break;
569 case KVM_REG_MIPS_FCR_IR:
570 if (!kvm_mips_guest_has_fpu(&vcpu->arch))
571 return -EINVAL;
572 v = boot_cpu_data.fpu_id;
573 break;
574 case KVM_REG_MIPS_FCR_CSR:
575 if (!kvm_mips_guest_has_fpu(&vcpu->arch))
576 return -EINVAL;
577 v = fpu->fcr31;
578 break;
579
580 /* Co-processor 0 registers */
546 case KVM_REG_MIPS_CP0_INDEX: 581 case KVM_REG_MIPS_CP0_INDEX:
547 v = (long)kvm_read_c0_guest_index(cop0); 582 v = (long)kvm_read_c0_guest_index(cop0);
548 break; 583 break;
@@ -636,7 +671,9 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
636 const struct kvm_one_reg *reg) 671 const struct kvm_one_reg *reg)
637{ 672{
638 struct mips_coproc *cop0 = vcpu->arch.cop0; 673 struct mips_coproc *cop0 = vcpu->arch.cop0;
639 u64 v; 674 struct mips_fpu_struct *fpu = &vcpu->arch.fpu;
675 s64 v;
676 unsigned int idx;
640 677
641 if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) { 678 if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) {
642 u64 __user *uaddr64 = (u64 __user *)(long)reg->addr; 679 u64 __user *uaddr64 = (u64 __user *)(long)reg->addr;
@@ -655,6 +692,7 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
655 } 692 }
656 693
657 switch (reg->id) { 694 switch (reg->id) {
695 /* General purpose registers */
658 case KVM_REG_MIPS_R0: 696 case KVM_REG_MIPS_R0:
659 /* Silently ignore requests to set $0 */ 697 /* Silently ignore requests to set $0 */
660 break; 698 break;
@@ -671,6 +709,38 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
671 vcpu->arch.pc = v; 709 vcpu->arch.pc = v;
672 break; 710 break;
673 711
712 /* Floating point registers */
713 case KVM_REG_MIPS_FPR_32(0) ... KVM_REG_MIPS_FPR_32(31):
714 if (!kvm_mips_guest_has_fpu(&vcpu->arch))
715 return -EINVAL;
716 idx = reg->id - KVM_REG_MIPS_FPR_32(0);
717 /* Odd singles in top of even double when FR=0 */
718 if (kvm_read_c0_guest_status(cop0) & ST0_FR)
719 set_fpr32(&fpu->fpr[idx], 0, v);
720 else
721 set_fpr32(&fpu->fpr[idx & ~1], idx & 1, v);
722 break;
723 case KVM_REG_MIPS_FPR_64(0) ... KVM_REG_MIPS_FPR_64(31):
724 if (!kvm_mips_guest_has_fpu(&vcpu->arch))
725 return -EINVAL;
726 idx = reg->id - KVM_REG_MIPS_FPR_64(0);
727 /* Can't access odd doubles in FR=0 mode */
728 if (idx & 1 && !(kvm_read_c0_guest_status(cop0) & ST0_FR))
729 return -EINVAL;
730 set_fpr64(&fpu->fpr[idx], 0, v);
731 break;
732 case KVM_REG_MIPS_FCR_IR:
733 if (!kvm_mips_guest_has_fpu(&vcpu->arch))
734 return -EINVAL;
735 /* Read-only */
736 break;
737 case KVM_REG_MIPS_FCR_CSR:
738 if (!kvm_mips_guest_has_fpu(&vcpu->arch))
739 return -EINVAL;
740 fpu->fcr31 = v;
741 break;
742
743 /* Co-processor 0 registers */
674 case KVM_REG_MIPS_CP0_INDEX: 744 case KVM_REG_MIPS_CP0_INDEX:
675 kvm_write_c0_guest_index(cop0, v); 745 kvm_write_c0_guest_index(cop0, v);
676 break; 746 break;