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:21 -0400 |
commit | ab86bd600400357ffa0dfdb1797f587476d01352 (patch) | |
tree | 265d24436dc03ac0e1ff2fa3a1652feb3346b6ff | |
parent | c2537ed9fb8e17d713e5e67fcede047699d25814 (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
-rw-r--r-- | Documentation/virtual/kvm/api.txt | 12 | ||||
-rw-r--r-- | arch/mips/include/uapi/asm/kvm.h | 12 | ||||
-rw-r--r-- | arch/mips/kvm/mips.c | 65 |
3 files changed, 86 insertions, 3 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index a1e9bfa5fe9e..62809871814b 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt | |||
@@ -1981,8 +1981,11 @@ registers, find a list below: | |||
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 | 1982 | MIPS | KVM_REG_MIPS_FPR_32(0..31) | 32 |
1983 | MIPS | KVM_REG_MIPS_FPR_64(0..31) | 64 | 1983 | MIPS | KVM_REG_MIPS_FPR_64(0..31) | 64 |
1984 | MIPS | KVM_REG_MIPS_VEC_128(0..31) | 128 | ||
1984 | MIPS | KVM_REG_MIPS_FCR_IR | 32 | 1985 | MIPS | KVM_REG_MIPS_FCR_IR | 32 |
1985 | MIPS | KVM_REG_MIPS_FCR_CSR | 32 | 1986 | MIPS | KVM_REG_MIPS_FCR_CSR | 32 |
1987 | MIPS | KVM_REG_MIPS_MSA_IR | 32 | ||
1988 | MIPS | KVM_REG_MIPS_MSA_CSR | 32 | ||
1986 | 1989 | ||
1987 | ARM registers are mapped using the lower 32 bits. The upper 16 of that | 1990 | ARM registers are mapped using the lower 32 bits. The upper 16 of that |
1988 | is the register group type, or coprocessor number: | 1991 | is the register group type, or coprocessor number: |
@@ -2040,14 +2043,21 @@ MIPS FPU registers (see KVM_REG_MIPS_FPR_{32,64}() above) have the following | |||
2040 | id bit patterns depending on the size of the register being accessed. They are | 2043 | id bit patterns depending on the size of the register being accessed. They are |
2041 | always accessed according to the current guest FPU mode (Status.FR and | 2044 | always accessed according to the current guest FPU mode (Status.FR and |
2042 | Config5.FRE), i.e. as the guest would see them, and they become unpredictable | 2045 | Config5.FRE), i.e. as the guest would see them, and they become unpredictable |
2043 | if the guest FPU mode is changed: | 2046 | if the guest FPU mode is changed. MIPS SIMD Architecture (MSA) vector |
2047 | registers (see KVM_REG_MIPS_VEC_128() above) have similar patterns as they | ||
2048 | overlap the FPU registers: | ||
2044 | 0x7020 0000 0003 00 <0:3> <reg:5> (32-bit FPU registers) | 2049 | 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) | 2050 | 0x7030 0000 0003 00 <0:3> <reg:5> (64-bit FPU registers) |
2051 | 0x7040 0000 0003 00 <0:3> <reg:5> (128-bit MSA vector registers) | ||
2046 | 2052 | ||
2047 | MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the | 2053 | MIPS FPU control registers (see KVM_REG_MIPS_FCR_{IR,CSR} above) have the |
2048 | following id bit patterns: | 2054 | following id bit patterns: |
2049 | 0x7020 0000 0003 01 <0:3> <reg:5> | 2055 | 0x7020 0000 0003 01 <0:3> <reg:5> |
2050 | 2056 | ||
2057 | MIPS MSA control registers (see KVM_REG_MIPS_MSA_{IR,CSR} above) have the | ||
2058 | following id bit patterns: | ||
2059 | 0x7020 0000 0003 02 <0:3> <reg:5> | ||
2060 | |||
2051 | 2061 | ||
2052 | 4.69 KVM_GET_ONE_REG | 2062 | 4.69 KVM_GET_ONE_REG |
2053 | 2063 | ||
diff --git a/arch/mips/include/uapi/asm/kvm.h b/arch/mips/include/uapi/asm/kvm.h index 401e6a6f8bb8..6985eb59b085 100644 --- a/arch/mips/include/uapi/asm/kvm.h +++ b/arch/mips/include/uapi/asm/kvm.h | |||
@@ -58,7 +58,7 @@ struct kvm_fpu { | |||
58 | * | 58 | * |
59 | * Register set = 2: KVM specific registers (see definitions below). | 59 | * Register set = 2: KVM specific registers (see definitions below). |
60 | * | 60 | * |
61 | * Register set = 3: FPU registers (see definitions below). | 61 | * Register set = 3: FPU / MSA registers (see definitions below). |
62 | * | 62 | * |
63 | * 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 |
64 | * have its own identifier in bits[31..16]. | 64 | * have its own identifier in bits[31..16]. |
@@ -148,7 +148,7 @@ struct kvm_fpu { | |||
148 | 148 | ||
149 | 149 | ||
150 | /* | 150 | /* |
151 | * KVM_REG_MIPS_FPU - Floating Point registers. | 151 | * KVM_REG_MIPS_FPU - Floating Point and MIPS SIMD Architecture (MSA) registers. |
152 | * | 152 | * |
153 | * bits[15..8] - Register subset (see definitions below). | 153 | * bits[15..8] - Register subset (see definitions below). |
154 | * bits[7..5] - Must be zero. | 154 | * bits[7..5] - Must be zero. |
@@ -157,12 +157,14 @@ struct kvm_fpu { | |||
157 | 157 | ||
158 | #define KVM_REG_MIPS_FPR (KVM_REG_MIPS_FPU | 0x0000000000000000ULL) | 158 | #define KVM_REG_MIPS_FPR (KVM_REG_MIPS_FPU | 0x0000000000000000ULL) |
159 | #define KVM_REG_MIPS_FCR (KVM_REG_MIPS_FPU | 0x0000000000000100ULL) | 159 | #define KVM_REG_MIPS_FCR (KVM_REG_MIPS_FPU | 0x0000000000000100ULL) |
160 | #define KVM_REG_MIPS_MSACR (KVM_REG_MIPS_FPU | 0x0000000000000200ULL) | ||
160 | 161 | ||
161 | /* | 162 | /* |
162 | * KVM_REG_MIPS_FPR - Floating point / Vector registers. | 163 | * KVM_REG_MIPS_FPR - Floating point / Vector registers. |
163 | */ | 164 | */ |
164 | #define KVM_REG_MIPS_FPR_32(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U32 | (n)) | 165 | #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 | #define KVM_REG_MIPS_FPR_64(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U64 | (n)) |
167 | #define KVM_REG_MIPS_VEC_128(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U128 | (n)) | ||
166 | 168 | ||
167 | /* | 169 | /* |
168 | * KVM_REG_MIPS_FCR - Floating point control registers. | 170 | * KVM_REG_MIPS_FCR - Floating point control registers. |
@@ -170,6 +172,12 @@ struct kvm_fpu { | |||
170 | #define KVM_REG_MIPS_FCR_IR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 0) | 172 | #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) | 173 | #define KVM_REG_MIPS_FCR_CSR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 31) |
172 | 174 | ||
175 | /* | ||
176 | * KVM_REG_MIPS_MSACR - MIPS SIMD Architecture (MSA) control registers. | ||
177 | */ | ||
178 | #define KVM_REG_MIPS_MSA_IR (KVM_REG_MIPS_MSACR | KVM_REG_SIZE_U32 | 0) | ||
179 | #define KVM_REG_MIPS_MSA_CSR (KVM_REG_MIPS_MSACR | KVM_REG_SIZE_U32 | 1) | ||
180 | |||
173 | 181 | ||
174 | /* | 182 | /* |
175 | * KVM MIPS specific structures and definitions | 183 | * KVM MIPS specific structures and definitions |
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); |