aboutsummaryrefslogtreecommitdiffstats
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
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
-rw-r--r--Documentation/virtual/kvm/api.txt16
-rw-r--r--arch/mips/include/uapi/asm/kvm.h37
-rw-r--r--arch/mips/kvm/mips.c72
3 files changed, 114 insertions, 11 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 3f295a04b09f..f3c198360785 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1979,6 +1979,10 @@ registers, find a list below:
1979 MIPS | KVM_REG_MIPS_COUNT_CTL | 64 1979 MIPS | KVM_REG_MIPS_COUNT_CTL | 64
1980 MIPS | KVM_REG_MIPS_COUNT_RESUME | 64 1980 MIPS | KVM_REG_MIPS_COUNT_RESUME | 64
1981 MIPS | KVM_REG_MIPS_COUNT_HZ | 64 1981 MIPS | KVM_REG_MIPS_COUNT_HZ | 64
1982 MIPS | KVM_REG_MIPS_FPR_32(0..31) | 32
1983 MIPS | KVM_REG_MIPS_FPR_64(0..31) | 64
1984 MIPS | KVM_REG_MIPS_FCR_IR | 32
1985 MIPS | KVM_REG_MIPS_FCR_CSR | 32
1982 1986
1983ARM registers are mapped using the lower 32 bits. The upper 16 of that 1987ARM registers are mapped using the lower 32 bits. The upper 16 of that
1984is the register group type, or coprocessor number: 1988is the register group type, or coprocessor number:
@@ -2032,6 +2036,18 @@ patterns depending on whether they're 32-bit or 64-bit registers:
2032MIPS KVM control registers (see above) have the following id bit patterns: 2036MIPS KVM control registers (see above) have the following id bit patterns:
2033 0x7030 0000 0002 <reg:16> 2037 0x7030 0000 0002 <reg:16>
2034 2038
2039MIPS FPU registers (see KVM_REG_MIPS_FPR_{32,64}() above) have the following
2040id bit patterns depending on the size of the register being accessed. They are
2041always accessed according to the current guest FPU mode (Status.FR and
2042Config5.FRE), i.e. as the guest would see them, and they become unpredictable
2043if the guest FPU mode is changed:
2044 0x7020 0000 0003 00 <0:3> <reg:5> (32-bit FPU registers)
2045 0x7030 0000 0003 00 <0:3> <reg:5> (64-bit FPU registers)
2046
2047MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the
2048following id bit patterns:
2049 0x7020 0000 0003 01 <0:3> <reg:5>
2050
2035 2051
20364.69 KVM_GET_ONE_REG 20524.69 KVM_GET_ONE_REG
2037 2053
diff --git a/arch/mips/include/uapi/asm/kvm.h b/arch/mips/include/uapi/asm/kvm.h
index 75d6d8557e57..401e6a6f8bb8 100644
--- a/arch/mips/include/uapi/asm/kvm.h
+++ b/arch/mips/include/uapi/asm/kvm.h
@@ -36,18 +36,8 @@ struct kvm_regs {
36 36
37/* 37/*
38 * for KVM_GET_FPU and KVM_SET_FPU 38 * for KVM_GET_FPU and KVM_SET_FPU
39 *
40 * If Status[FR] is zero (32-bit FPU), the upper 32-bits of the FPRs
41 * are zero filled.
42 */ 39 */
43struct kvm_fpu { 40struct kvm_fpu {
44 __u64 fpr[32];
45 __u32 fir;
46 __u32 fccr;
47 __u32 fexr;
48 __u32 fenr;
49 __u32 fcsr;
50 __u32 pad;
51}; 41};
52 42
53 43
@@ -68,6 +58,8 @@ struct kvm_fpu {
68 * 58 *
69 * Register set = 2: KVM specific registers (see definitions below). 59 * Register set = 2: KVM specific registers (see definitions below).
70 * 60 *
61 * Register set = 3: FPU registers (see definitions below).
62 *
71 * Other sets registers may be added in the future. Each set would 63 * Other sets registers may be added in the future. Each set would
72 * have its own identifier in bits[31..16]. 64 * have its own identifier in bits[31..16].
73 */ 65 */
@@ -75,6 +67,7 @@ struct kvm_fpu {
75#define KVM_REG_MIPS_GP (KVM_REG_MIPS | 0x0000000000000000ULL) 67#define KVM_REG_MIPS_GP (KVM_REG_MIPS | 0x0000000000000000ULL)
76#define KVM_REG_MIPS_CP0 (KVM_REG_MIPS | 0x0000000000010000ULL) 68#define KVM_REG_MIPS_CP0 (KVM_REG_MIPS | 0x0000000000010000ULL)
77#define KVM_REG_MIPS_KVM (KVM_REG_MIPS | 0x0000000000020000ULL) 69#define KVM_REG_MIPS_KVM (KVM_REG_MIPS | 0x0000000000020000ULL)
70#define KVM_REG_MIPS_FPU (KVM_REG_MIPS | 0x0000000000030000ULL)
78 71
79 72
80/* 73/*
@@ -155,6 +148,30 @@ struct kvm_fpu {
155 148
156 149
157/* 150/*
151 * KVM_REG_MIPS_FPU - Floating Point registers.
152 *
153 * bits[15..8] - Register subset (see definitions below).
154 * bits[7..5] - Must be zero.
155 * bits[4..0] - Register number within register subset.
156 */
157
158#define KVM_REG_MIPS_FPR (KVM_REG_MIPS_FPU | 0x0000000000000000ULL)
159#define KVM_REG_MIPS_FCR (KVM_REG_MIPS_FPU | 0x0000000000000100ULL)
160
161/*
162 * KVM_REG_MIPS_FPR - Floating point / Vector registers.
163 */
164#define KVM_REG_MIPS_FPR_32(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U32 | (n))
165#define KVM_REG_MIPS_FPR_64(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U64 | (n))
166
167/*
168 * KVM_REG_MIPS_FCR - Floating point control registers.
169 */
170#define KVM_REG_MIPS_FCR_IR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 0)
171#define KVM_REG_MIPS_FCR_CSR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 31)
172
173
174/*
158 * KVM MIPS specific structures and definitions 175 * KVM MIPS specific structures and definitions
159 * 176 *
160 */ 177 */
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;