diff options
author | James Hogan <james.hogan@imgtec.com> | 2014-12-02 10:48:24 -0500 |
---|---|---|
committer | James Hogan <james.hogan@imgtec.com> | 2015-03-27 17:25:17 -0400 |
commit | 379245cdf1d1efc1eccc38bf0cc985dae232123d (patch) | |
tree | 6b61c5f80129fac86533f2e7cc3d05e8320324b8 /arch/mips/kvm | |
parent | 1c0cd66adbac8aa339b9521eceb18b00d1b0699e (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.c | 72 |
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; |