diff options
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/include/asm/asmmacro-32.h | 128 | ||||
-rw-r--r-- | arch/mips/include/asm/asmmacro.h | 218 | ||||
-rw-r--r-- | arch/mips/include/asm/fpu.h | 20 | ||||
-rw-r--r-- | arch/mips/include/asm/kdebug.h | 3 | ||||
-rw-r--r-- | arch/mips/include/asm/kvm_host.h | 125 | ||||
-rw-r--r-- | arch/mips/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/mips/include/uapi/asm/kvm.h | 164 | ||||
-rw-r--r-- | arch/mips/kernel/asm-offsets.c | 105 | ||||
-rw-r--r-- | arch/mips/kernel/genex.S | 15 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace.c | 30 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_fpu.S | 2 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 33 | ||||
-rw-r--r-- | arch/mips/kvm/Makefile | 8 | ||||
-rw-r--r-- | arch/mips/kvm/emulate.c | 332 | ||||
-rw-r--r-- | arch/mips/kvm/fpu.S | 122 | ||||
-rw-r--r-- | arch/mips/kvm/locore.S | 38 | ||||
-rw-r--r-- | arch/mips/kvm/mips.c | 472 | ||||
-rw-r--r-- | arch/mips/kvm/msa.S | 161 | ||||
-rw-r--r-- | arch/mips/kvm/stats.c | 4 | ||||
-rw-r--r-- | arch/mips/kvm/tlb.c | 6 | ||||
-rw-r--r-- | arch/mips/kvm/trap_emul.c | 199 |
21 files changed, 1821 insertions, 366 deletions
diff --git a/arch/mips/include/asm/asmmacro-32.h b/arch/mips/include/asm/asmmacro-32.h index cdac7b3eeaf7..80386470d3a4 100644 --- a/arch/mips/include/asm/asmmacro-32.h +++ b/arch/mips/include/asm/asmmacro-32.h | |||
@@ -16,38 +16,38 @@ | |||
16 | .set push | 16 | .set push |
17 | SET_HARDFLOAT | 17 | SET_HARDFLOAT |
18 | cfc1 \tmp, fcr31 | 18 | cfc1 \tmp, fcr31 |
19 | swc1 $f0, THREAD_FPR0_LS64(\thread) | 19 | swc1 $f0, THREAD_FPR0(\thread) |
20 | swc1 $f1, THREAD_FPR1_LS64(\thread) | 20 | swc1 $f1, THREAD_FPR1(\thread) |
21 | swc1 $f2, THREAD_FPR2_LS64(\thread) | 21 | swc1 $f2, THREAD_FPR2(\thread) |
22 | swc1 $f3, THREAD_FPR3_LS64(\thread) | 22 | swc1 $f3, THREAD_FPR3(\thread) |
23 | swc1 $f4, THREAD_FPR4_LS64(\thread) | 23 | swc1 $f4, THREAD_FPR4(\thread) |
24 | swc1 $f5, THREAD_FPR5_LS64(\thread) | 24 | swc1 $f5, THREAD_FPR5(\thread) |
25 | swc1 $f6, THREAD_FPR6_LS64(\thread) | 25 | swc1 $f6, THREAD_FPR6(\thread) |
26 | swc1 $f7, THREAD_FPR7_LS64(\thread) | 26 | swc1 $f7, THREAD_FPR7(\thread) |
27 | swc1 $f8, THREAD_FPR8_LS64(\thread) | 27 | swc1 $f8, THREAD_FPR8(\thread) |
28 | swc1 $f9, THREAD_FPR9_LS64(\thread) | 28 | swc1 $f9, THREAD_FPR9(\thread) |
29 | swc1 $f10, THREAD_FPR10_LS64(\thread) | 29 | swc1 $f10, THREAD_FPR10(\thread) |
30 | swc1 $f11, THREAD_FPR11_LS64(\thread) | 30 | swc1 $f11, THREAD_FPR11(\thread) |
31 | swc1 $f12, THREAD_FPR12_LS64(\thread) | 31 | swc1 $f12, THREAD_FPR12(\thread) |
32 | swc1 $f13, THREAD_FPR13_LS64(\thread) | 32 | swc1 $f13, THREAD_FPR13(\thread) |
33 | swc1 $f14, THREAD_FPR14_LS64(\thread) | 33 | swc1 $f14, THREAD_FPR14(\thread) |
34 | swc1 $f15, THREAD_FPR15_LS64(\thread) | 34 | swc1 $f15, THREAD_FPR15(\thread) |
35 | swc1 $f16, THREAD_FPR16_LS64(\thread) | 35 | swc1 $f16, THREAD_FPR16(\thread) |
36 | swc1 $f17, THREAD_FPR17_LS64(\thread) | 36 | swc1 $f17, THREAD_FPR17(\thread) |
37 | swc1 $f18, THREAD_FPR18_LS64(\thread) | 37 | swc1 $f18, THREAD_FPR18(\thread) |
38 | swc1 $f19, THREAD_FPR19_LS64(\thread) | 38 | swc1 $f19, THREAD_FPR19(\thread) |
39 | swc1 $f20, THREAD_FPR20_LS64(\thread) | 39 | swc1 $f20, THREAD_FPR20(\thread) |
40 | swc1 $f21, THREAD_FPR21_LS64(\thread) | 40 | swc1 $f21, THREAD_FPR21(\thread) |
41 | swc1 $f22, THREAD_FPR22_LS64(\thread) | 41 | swc1 $f22, THREAD_FPR22(\thread) |
42 | swc1 $f23, THREAD_FPR23_LS64(\thread) | 42 | swc1 $f23, THREAD_FPR23(\thread) |
43 | swc1 $f24, THREAD_FPR24_LS64(\thread) | 43 | swc1 $f24, THREAD_FPR24(\thread) |
44 | swc1 $f25, THREAD_FPR25_LS64(\thread) | 44 | swc1 $f25, THREAD_FPR25(\thread) |
45 | swc1 $f26, THREAD_FPR26_LS64(\thread) | 45 | swc1 $f26, THREAD_FPR26(\thread) |
46 | swc1 $f27, THREAD_FPR27_LS64(\thread) | 46 | swc1 $f27, THREAD_FPR27(\thread) |
47 | swc1 $f28, THREAD_FPR28_LS64(\thread) | 47 | swc1 $f28, THREAD_FPR28(\thread) |
48 | swc1 $f29, THREAD_FPR29_LS64(\thread) | 48 | swc1 $f29, THREAD_FPR29(\thread) |
49 | swc1 $f30, THREAD_FPR30_LS64(\thread) | 49 | swc1 $f30, THREAD_FPR30(\thread) |
50 | swc1 $f31, THREAD_FPR31_LS64(\thread) | 50 | swc1 $f31, THREAD_FPR31(\thread) |
51 | sw \tmp, THREAD_FCR31(\thread) | 51 | sw \tmp, THREAD_FCR31(\thread) |
52 | .set pop | 52 | .set pop |
53 | .endm | 53 | .endm |
@@ -56,38 +56,38 @@ | |||
56 | .set push | 56 | .set push |
57 | SET_HARDFLOAT | 57 | SET_HARDFLOAT |
58 | lw \tmp, THREAD_FCR31(\thread) | 58 | lw \tmp, THREAD_FCR31(\thread) |
59 | lwc1 $f0, THREAD_FPR0_LS64(\thread) | 59 | lwc1 $f0, THREAD_FPR0(\thread) |
60 | lwc1 $f1, THREAD_FPR1_LS64(\thread) | 60 | lwc1 $f1, THREAD_FPR1(\thread) |
61 | lwc1 $f2, THREAD_FPR2_LS64(\thread) | 61 | lwc1 $f2, THREAD_FPR2(\thread) |
62 | lwc1 $f3, THREAD_FPR3_LS64(\thread) | 62 | lwc1 $f3, THREAD_FPR3(\thread) |
63 | lwc1 $f4, THREAD_FPR4_LS64(\thread) | 63 | lwc1 $f4, THREAD_FPR4(\thread) |
64 | lwc1 $f5, THREAD_FPR5_LS64(\thread) | 64 | lwc1 $f5, THREAD_FPR5(\thread) |
65 | lwc1 $f6, THREAD_FPR6_LS64(\thread) | 65 | lwc1 $f6, THREAD_FPR6(\thread) |
66 | lwc1 $f7, THREAD_FPR7_LS64(\thread) | 66 | lwc1 $f7, THREAD_FPR7(\thread) |
67 | lwc1 $f8, THREAD_FPR8_LS64(\thread) | 67 | lwc1 $f8, THREAD_FPR8(\thread) |
68 | lwc1 $f9, THREAD_FPR9_LS64(\thread) | 68 | lwc1 $f9, THREAD_FPR9(\thread) |
69 | lwc1 $f10, THREAD_FPR10_LS64(\thread) | 69 | lwc1 $f10, THREAD_FPR10(\thread) |
70 | lwc1 $f11, THREAD_FPR11_LS64(\thread) | 70 | lwc1 $f11, THREAD_FPR11(\thread) |
71 | lwc1 $f12, THREAD_FPR12_LS64(\thread) | 71 | lwc1 $f12, THREAD_FPR12(\thread) |
72 | lwc1 $f13, THREAD_FPR13_LS64(\thread) | 72 | lwc1 $f13, THREAD_FPR13(\thread) |
73 | lwc1 $f14, THREAD_FPR14_LS64(\thread) | 73 | lwc1 $f14, THREAD_FPR14(\thread) |
74 | lwc1 $f15, THREAD_FPR15_LS64(\thread) | 74 | lwc1 $f15, THREAD_FPR15(\thread) |
75 | lwc1 $f16, THREAD_FPR16_LS64(\thread) | 75 | lwc1 $f16, THREAD_FPR16(\thread) |
76 | lwc1 $f17, THREAD_FPR17_LS64(\thread) | 76 | lwc1 $f17, THREAD_FPR17(\thread) |
77 | lwc1 $f18, THREAD_FPR18_LS64(\thread) | 77 | lwc1 $f18, THREAD_FPR18(\thread) |
78 | lwc1 $f19, THREAD_FPR19_LS64(\thread) | 78 | lwc1 $f19, THREAD_FPR19(\thread) |
79 | lwc1 $f20, THREAD_FPR20_LS64(\thread) | 79 | lwc1 $f20, THREAD_FPR20(\thread) |
80 | lwc1 $f21, THREAD_FPR21_LS64(\thread) | 80 | lwc1 $f21, THREAD_FPR21(\thread) |
81 | lwc1 $f22, THREAD_FPR22_LS64(\thread) | 81 | lwc1 $f22, THREAD_FPR22(\thread) |
82 | lwc1 $f23, THREAD_FPR23_LS64(\thread) | 82 | lwc1 $f23, THREAD_FPR23(\thread) |
83 | lwc1 $f24, THREAD_FPR24_LS64(\thread) | 83 | lwc1 $f24, THREAD_FPR24(\thread) |
84 | lwc1 $f25, THREAD_FPR25_LS64(\thread) | 84 | lwc1 $f25, THREAD_FPR25(\thread) |
85 | lwc1 $f26, THREAD_FPR26_LS64(\thread) | 85 | lwc1 $f26, THREAD_FPR26(\thread) |
86 | lwc1 $f27, THREAD_FPR27_LS64(\thread) | 86 | lwc1 $f27, THREAD_FPR27(\thread) |
87 | lwc1 $f28, THREAD_FPR28_LS64(\thread) | 87 | lwc1 $f28, THREAD_FPR28(\thread) |
88 | lwc1 $f29, THREAD_FPR29_LS64(\thread) | 88 | lwc1 $f29, THREAD_FPR29(\thread) |
89 | lwc1 $f30, THREAD_FPR30_LS64(\thread) | 89 | lwc1 $f30, THREAD_FPR30(\thread) |
90 | lwc1 $f31, THREAD_FPR31_LS64(\thread) | 90 | lwc1 $f31, THREAD_FPR31(\thread) |
91 | ctc1 \tmp, fcr31 | 91 | ctc1 \tmp, fcr31 |
92 | .set pop | 92 | .set pop |
93 | .endm | 93 | .endm |
diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 0cae4595e985..6156ac8c4cfb 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h | |||
@@ -60,22 +60,22 @@ | |||
60 | .set push | 60 | .set push |
61 | SET_HARDFLOAT | 61 | SET_HARDFLOAT |
62 | cfc1 \tmp, fcr31 | 62 | cfc1 \tmp, fcr31 |
63 | sdc1 $f0, THREAD_FPR0_LS64(\thread) | 63 | sdc1 $f0, THREAD_FPR0(\thread) |
64 | sdc1 $f2, THREAD_FPR2_LS64(\thread) | 64 | sdc1 $f2, THREAD_FPR2(\thread) |
65 | sdc1 $f4, THREAD_FPR4_LS64(\thread) | 65 | sdc1 $f4, THREAD_FPR4(\thread) |
66 | sdc1 $f6, THREAD_FPR6_LS64(\thread) | 66 | sdc1 $f6, THREAD_FPR6(\thread) |
67 | sdc1 $f8, THREAD_FPR8_LS64(\thread) | 67 | sdc1 $f8, THREAD_FPR8(\thread) |
68 | sdc1 $f10, THREAD_FPR10_LS64(\thread) | 68 | sdc1 $f10, THREAD_FPR10(\thread) |
69 | sdc1 $f12, THREAD_FPR12_LS64(\thread) | 69 | sdc1 $f12, THREAD_FPR12(\thread) |
70 | sdc1 $f14, THREAD_FPR14_LS64(\thread) | 70 | sdc1 $f14, THREAD_FPR14(\thread) |
71 | sdc1 $f16, THREAD_FPR16_LS64(\thread) | 71 | sdc1 $f16, THREAD_FPR16(\thread) |
72 | sdc1 $f18, THREAD_FPR18_LS64(\thread) | 72 | sdc1 $f18, THREAD_FPR18(\thread) |
73 | sdc1 $f20, THREAD_FPR20_LS64(\thread) | 73 | sdc1 $f20, THREAD_FPR20(\thread) |
74 | sdc1 $f22, THREAD_FPR22_LS64(\thread) | 74 | sdc1 $f22, THREAD_FPR22(\thread) |
75 | sdc1 $f24, THREAD_FPR24_LS64(\thread) | 75 | sdc1 $f24, THREAD_FPR24(\thread) |
76 | sdc1 $f26, THREAD_FPR26_LS64(\thread) | 76 | sdc1 $f26, THREAD_FPR26(\thread) |
77 | sdc1 $f28, THREAD_FPR28_LS64(\thread) | 77 | sdc1 $f28, THREAD_FPR28(\thread) |
78 | sdc1 $f30, THREAD_FPR30_LS64(\thread) | 78 | sdc1 $f30, THREAD_FPR30(\thread) |
79 | sw \tmp, THREAD_FCR31(\thread) | 79 | sw \tmp, THREAD_FCR31(\thread) |
80 | .set pop | 80 | .set pop |
81 | .endm | 81 | .endm |
@@ -84,22 +84,22 @@ | |||
84 | .set push | 84 | .set push |
85 | .set mips64r2 | 85 | .set mips64r2 |
86 | SET_HARDFLOAT | 86 | SET_HARDFLOAT |
87 | sdc1 $f1, THREAD_FPR1_LS64(\thread) | 87 | sdc1 $f1, THREAD_FPR1(\thread) |
88 | sdc1 $f3, THREAD_FPR3_LS64(\thread) | 88 | sdc1 $f3, THREAD_FPR3(\thread) |
89 | sdc1 $f5, THREAD_FPR5_LS64(\thread) | 89 | sdc1 $f5, THREAD_FPR5(\thread) |
90 | sdc1 $f7, THREAD_FPR7_LS64(\thread) | 90 | sdc1 $f7, THREAD_FPR7(\thread) |
91 | sdc1 $f9, THREAD_FPR9_LS64(\thread) | 91 | sdc1 $f9, THREAD_FPR9(\thread) |
92 | sdc1 $f11, THREAD_FPR11_LS64(\thread) | 92 | sdc1 $f11, THREAD_FPR11(\thread) |
93 | sdc1 $f13, THREAD_FPR13_LS64(\thread) | 93 | sdc1 $f13, THREAD_FPR13(\thread) |
94 | sdc1 $f15, THREAD_FPR15_LS64(\thread) | 94 | sdc1 $f15, THREAD_FPR15(\thread) |
95 | sdc1 $f17, THREAD_FPR17_LS64(\thread) | 95 | sdc1 $f17, THREAD_FPR17(\thread) |
96 | sdc1 $f19, THREAD_FPR19_LS64(\thread) | 96 | sdc1 $f19, THREAD_FPR19(\thread) |
97 | sdc1 $f21, THREAD_FPR21_LS64(\thread) | 97 | sdc1 $f21, THREAD_FPR21(\thread) |
98 | sdc1 $f23, THREAD_FPR23_LS64(\thread) | 98 | sdc1 $f23, THREAD_FPR23(\thread) |
99 | sdc1 $f25, THREAD_FPR25_LS64(\thread) | 99 | sdc1 $f25, THREAD_FPR25(\thread) |
100 | sdc1 $f27, THREAD_FPR27_LS64(\thread) | 100 | sdc1 $f27, THREAD_FPR27(\thread) |
101 | sdc1 $f29, THREAD_FPR29_LS64(\thread) | 101 | sdc1 $f29, THREAD_FPR29(\thread) |
102 | sdc1 $f31, THREAD_FPR31_LS64(\thread) | 102 | sdc1 $f31, THREAD_FPR31(\thread) |
103 | .set pop | 103 | .set pop |
104 | .endm | 104 | .endm |
105 | 105 | ||
@@ -118,22 +118,22 @@ | |||
118 | .set push | 118 | .set push |
119 | SET_HARDFLOAT | 119 | SET_HARDFLOAT |
120 | lw \tmp, THREAD_FCR31(\thread) | 120 | lw \tmp, THREAD_FCR31(\thread) |
121 | ldc1 $f0, THREAD_FPR0_LS64(\thread) | 121 | ldc1 $f0, THREAD_FPR0(\thread) |
122 | ldc1 $f2, THREAD_FPR2_LS64(\thread) | 122 | ldc1 $f2, THREAD_FPR2(\thread) |
123 | ldc1 $f4, THREAD_FPR4_LS64(\thread) | 123 | ldc1 $f4, THREAD_FPR4(\thread) |
124 | ldc1 $f6, THREAD_FPR6_LS64(\thread) | 124 | ldc1 $f6, THREAD_FPR6(\thread) |
125 | ldc1 $f8, THREAD_FPR8_LS64(\thread) | 125 | ldc1 $f8, THREAD_FPR8(\thread) |
126 | ldc1 $f10, THREAD_FPR10_LS64(\thread) | 126 | ldc1 $f10, THREAD_FPR10(\thread) |
127 | ldc1 $f12, THREAD_FPR12_LS64(\thread) | 127 | ldc1 $f12, THREAD_FPR12(\thread) |
128 | ldc1 $f14, THREAD_FPR14_LS64(\thread) | 128 | ldc1 $f14, THREAD_FPR14(\thread) |
129 | ldc1 $f16, THREAD_FPR16_LS64(\thread) | 129 | ldc1 $f16, THREAD_FPR16(\thread) |
130 | ldc1 $f18, THREAD_FPR18_LS64(\thread) | 130 | ldc1 $f18, THREAD_FPR18(\thread) |
131 | ldc1 $f20, THREAD_FPR20_LS64(\thread) | 131 | ldc1 $f20, THREAD_FPR20(\thread) |
132 | ldc1 $f22, THREAD_FPR22_LS64(\thread) | 132 | ldc1 $f22, THREAD_FPR22(\thread) |
133 | ldc1 $f24, THREAD_FPR24_LS64(\thread) | 133 | ldc1 $f24, THREAD_FPR24(\thread) |
134 | ldc1 $f26, THREAD_FPR26_LS64(\thread) | 134 | ldc1 $f26, THREAD_FPR26(\thread) |
135 | ldc1 $f28, THREAD_FPR28_LS64(\thread) | 135 | ldc1 $f28, THREAD_FPR28(\thread) |
136 | ldc1 $f30, THREAD_FPR30_LS64(\thread) | 136 | ldc1 $f30, THREAD_FPR30(\thread) |
137 | ctc1 \tmp, fcr31 | 137 | ctc1 \tmp, fcr31 |
138 | .endm | 138 | .endm |
139 | 139 | ||
@@ -141,22 +141,22 @@ | |||
141 | .set push | 141 | .set push |
142 | .set mips64r2 | 142 | .set mips64r2 |
143 | SET_HARDFLOAT | 143 | SET_HARDFLOAT |
144 | ldc1 $f1, THREAD_FPR1_LS64(\thread) | 144 | ldc1 $f1, THREAD_FPR1(\thread) |
145 | ldc1 $f3, THREAD_FPR3_LS64(\thread) | 145 | ldc1 $f3, THREAD_FPR3(\thread) |
146 | ldc1 $f5, THREAD_FPR5_LS64(\thread) | 146 | ldc1 $f5, THREAD_FPR5(\thread) |
147 | ldc1 $f7, THREAD_FPR7_LS64(\thread) | 147 | ldc1 $f7, THREAD_FPR7(\thread) |
148 | ldc1 $f9, THREAD_FPR9_LS64(\thread) | 148 | ldc1 $f9, THREAD_FPR9(\thread) |
149 | ldc1 $f11, THREAD_FPR11_LS64(\thread) | 149 | ldc1 $f11, THREAD_FPR11(\thread) |
150 | ldc1 $f13, THREAD_FPR13_LS64(\thread) | 150 | ldc1 $f13, THREAD_FPR13(\thread) |
151 | ldc1 $f15, THREAD_FPR15_LS64(\thread) | 151 | ldc1 $f15, THREAD_FPR15(\thread) |
152 | ldc1 $f17, THREAD_FPR17_LS64(\thread) | 152 | ldc1 $f17, THREAD_FPR17(\thread) |
153 | ldc1 $f19, THREAD_FPR19_LS64(\thread) | 153 | ldc1 $f19, THREAD_FPR19(\thread) |
154 | ldc1 $f21, THREAD_FPR21_LS64(\thread) | 154 | ldc1 $f21, THREAD_FPR21(\thread) |
155 | ldc1 $f23, THREAD_FPR23_LS64(\thread) | 155 | ldc1 $f23, THREAD_FPR23(\thread) |
156 | ldc1 $f25, THREAD_FPR25_LS64(\thread) | 156 | ldc1 $f25, THREAD_FPR25(\thread) |
157 | ldc1 $f27, THREAD_FPR27_LS64(\thread) | 157 | ldc1 $f27, THREAD_FPR27(\thread) |
158 | ldc1 $f29, THREAD_FPR29_LS64(\thread) | 158 | ldc1 $f29, THREAD_FPR29(\thread) |
159 | ldc1 $f31, THREAD_FPR31_LS64(\thread) | 159 | ldc1 $f31, THREAD_FPR31(\thread) |
160 | .set pop | 160 | .set pop |
161 | .endm | 161 | .endm |
162 | 162 | ||
@@ -211,6 +211,22 @@ | |||
211 | .endm | 211 | .endm |
212 | 212 | ||
213 | #ifdef TOOLCHAIN_SUPPORTS_MSA | 213 | #ifdef TOOLCHAIN_SUPPORTS_MSA |
214 | .macro _cfcmsa rd, cs | ||
215 | .set push | ||
216 | .set mips32r2 | ||
217 | .set msa | ||
218 | cfcmsa \rd, $\cs | ||
219 | .set pop | ||
220 | .endm | ||
221 | |||
222 | .macro _ctcmsa cd, rs | ||
223 | .set push | ||
224 | .set mips32r2 | ||
225 | .set msa | ||
226 | ctcmsa $\cd, \rs | ||
227 | .set pop | ||
228 | .endm | ||
229 | |||
214 | .macro ld_d wd, off, base | 230 | .macro ld_d wd, off, base |
215 | .set push | 231 | .set push |
216 | .set mips32r2 | 232 | .set mips32r2 |
@@ -227,35 +243,35 @@ | |||
227 | .set pop | 243 | .set pop |
228 | .endm | 244 | .endm |
229 | 245 | ||
230 | .macro copy_u_w rd, ws, n | 246 | .macro copy_u_w ws, n |
231 | .set push | 247 | .set push |
232 | .set mips32r2 | 248 | .set mips32r2 |
233 | .set msa | 249 | .set msa |
234 | copy_u.w \rd, $w\ws[\n] | 250 | copy_u.w $1, $w\ws[\n] |
235 | .set pop | 251 | .set pop |
236 | .endm | 252 | .endm |
237 | 253 | ||
238 | .macro copy_u_d rd, ws, n | 254 | .macro copy_u_d ws, n |
239 | .set push | 255 | .set push |
240 | .set mips64r2 | 256 | .set mips64r2 |
241 | .set msa | 257 | .set msa |
242 | copy_u.d \rd, $w\ws[\n] | 258 | copy_u.d $1, $w\ws[\n] |
243 | .set pop | 259 | .set pop |
244 | .endm | 260 | .endm |
245 | 261 | ||
246 | .macro insert_w wd, n, rs | 262 | .macro insert_w wd, n |
247 | .set push | 263 | .set push |
248 | .set mips32r2 | 264 | .set mips32r2 |
249 | .set msa | 265 | .set msa |
250 | insert.w $w\wd[\n], \rs | 266 | insert.w $w\wd[\n], $1 |
251 | .set pop | 267 | .set pop |
252 | .endm | 268 | .endm |
253 | 269 | ||
254 | .macro insert_d wd, n, rs | 270 | .macro insert_d wd, n |
255 | .set push | 271 | .set push |
256 | .set mips64r2 | 272 | .set mips64r2 |
257 | .set msa | 273 | .set msa |
258 | insert.d $w\wd[\n], \rs | 274 | insert.d $w\wd[\n], $1 |
259 | .set pop | 275 | .set pop |
260 | .endm | 276 | .endm |
261 | #else | 277 | #else |
@@ -283,7 +299,7 @@ | |||
283 | /* | 299 | /* |
284 | * Temporary until all toolchains in use include MSA support. | 300 | * Temporary until all toolchains in use include MSA support. |
285 | */ | 301 | */ |
286 | .macro cfcmsa rd, cs | 302 | .macro _cfcmsa rd, cs |
287 | .set push | 303 | .set push |
288 | .set noat | 304 | .set noat |
289 | SET_HARDFLOAT | 305 | SET_HARDFLOAT |
@@ -293,7 +309,7 @@ | |||
293 | .set pop | 309 | .set pop |
294 | .endm | 310 | .endm |
295 | 311 | ||
296 | .macro ctcmsa cd, rs | 312 | .macro _ctcmsa cd, rs |
297 | .set push | 313 | .set push |
298 | .set noat | 314 | .set noat |
299 | SET_HARDFLOAT | 315 | SET_HARDFLOAT |
@@ -320,44 +336,36 @@ | |||
320 | .set pop | 336 | .set pop |
321 | .endm | 337 | .endm |
322 | 338 | ||
323 | .macro copy_u_w rd, ws, n | 339 | .macro copy_u_w ws, n |
324 | .set push | 340 | .set push |
325 | .set noat | 341 | .set noat |
326 | SET_HARDFLOAT | 342 | SET_HARDFLOAT |
327 | .insn | 343 | .insn |
328 | .word COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11) | 344 | .word COPY_UW_MSA_INSN | (\n << 16) | (\ws << 11) |
329 | /* move triggers an assembler bug... */ | ||
330 | or \rd, $1, zero | ||
331 | .set pop | 345 | .set pop |
332 | .endm | 346 | .endm |
333 | 347 | ||
334 | .macro copy_u_d rd, ws, n | 348 | .macro copy_u_d ws, n |
335 | .set push | 349 | .set push |
336 | .set noat | 350 | .set noat |
337 | SET_HARDFLOAT | 351 | SET_HARDFLOAT |
338 | .insn | 352 | .insn |
339 | .word COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11) | 353 | .word COPY_UD_MSA_INSN | (\n << 16) | (\ws << 11) |
340 | /* move triggers an assembler bug... */ | ||
341 | or \rd, $1, zero | ||
342 | .set pop | 354 | .set pop |
343 | .endm | 355 | .endm |
344 | 356 | ||
345 | .macro insert_w wd, n, rs | 357 | .macro insert_w wd, n |
346 | .set push | 358 | .set push |
347 | .set noat | 359 | .set noat |
348 | SET_HARDFLOAT | 360 | SET_HARDFLOAT |
349 | /* move triggers an assembler bug... */ | ||
350 | or $1, \rs, zero | ||
351 | .word INSERT_W_MSA_INSN | (\n << 16) | (\wd << 6) | 361 | .word INSERT_W_MSA_INSN | (\n << 16) | (\wd << 6) |
352 | .set pop | 362 | .set pop |
353 | .endm | 363 | .endm |
354 | 364 | ||
355 | .macro insert_d wd, n, rs | 365 | .macro insert_d wd, n |
356 | .set push | 366 | .set push |
357 | .set noat | 367 | .set noat |
358 | SET_HARDFLOAT | 368 | SET_HARDFLOAT |
359 | /* move triggers an assembler bug... */ | ||
360 | or $1, \rs, zero | ||
361 | .word INSERT_D_MSA_INSN | (\n << 16) | (\wd << 6) | 369 | .word INSERT_D_MSA_INSN | (\n << 16) | (\wd << 6) |
362 | .set pop | 370 | .set pop |
363 | .endm | 371 | .endm |
@@ -399,7 +407,7 @@ | |||
399 | .set push | 407 | .set push |
400 | .set noat | 408 | .set noat |
401 | SET_HARDFLOAT | 409 | SET_HARDFLOAT |
402 | cfcmsa $1, MSA_CSR | 410 | _cfcmsa $1, MSA_CSR |
403 | sw $1, THREAD_MSA_CSR(\thread) | 411 | sw $1, THREAD_MSA_CSR(\thread) |
404 | .set pop | 412 | .set pop |
405 | .endm | 413 | .endm |
@@ -409,7 +417,7 @@ | |||
409 | .set noat | 417 | .set noat |
410 | SET_HARDFLOAT | 418 | SET_HARDFLOAT |
411 | lw $1, THREAD_MSA_CSR(\thread) | 419 | lw $1, THREAD_MSA_CSR(\thread) |
412 | ctcmsa MSA_CSR, $1 | 420 | _ctcmsa MSA_CSR, $1 |
413 | .set pop | 421 | .set pop |
414 | ld_d 0, THREAD_FPR0, \thread | 422 | ld_d 0, THREAD_FPR0, \thread |
415 | ld_d 1, THREAD_FPR1, \thread | 423 | ld_d 1, THREAD_FPR1, \thread |
@@ -452,9 +460,6 @@ | |||
452 | insert_w \wd, 2 | 460 | insert_w \wd, 2 |
453 | insert_w \wd, 3 | 461 | insert_w \wd, 3 |
454 | #endif | 462 | #endif |
455 | .if 31-\wd | ||
456 | msa_init_upper (\wd+1) | ||
457 | .endif | ||
458 | .endm | 463 | .endm |
459 | 464 | ||
460 | .macro msa_init_all_upper | 465 | .macro msa_init_all_upper |
@@ -463,6 +468,37 @@ | |||
463 | SET_HARDFLOAT | 468 | SET_HARDFLOAT |
464 | not $1, zero | 469 | not $1, zero |
465 | msa_init_upper 0 | 470 | msa_init_upper 0 |
471 | msa_init_upper 1 | ||
472 | msa_init_upper 2 | ||
473 | msa_init_upper 3 | ||
474 | msa_init_upper 4 | ||
475 | msa_init_upper 5 | ||
476 | msa_init_upper 6 | ||
477 | msa_init_upper 7 | ||
478 | msa_init_upper 8 | ||
479 | msa_init_upper 9 | ||
480 | msa_init_upper 10 | ||
481 | msa_init_upper 11 | ||
482 | msa_init_upper 12 | ||
483 | msa_init_upper 13 | ||
484 | msa_init_upper 14 | ||
485 | msa_init_upper 15 | ||
486 | msa_init_upper 16 | ||
487 | msa_init_upper 17 | ||
488 | msa_init_upper 18 | ||
489 | msa_init_upper 19 | ||
490 | msa_init_upper 20 | ||
491 | msa_init_upper 21 | ||
492 | msa_init_upper 22 | ||
493 | msa_init_upper 23 | ||
494 | msa_init_upper 24 | ||
495 | msa_init_upper 25 | ||
496 | msa_init_upper 26 | ||
497 | msa_init_upper 27 | ||
498 | msa_init_upper 28 | ||
499 | msa_init_upper 29 | ||
500 | msa_init_upper 30 | ||
501 | msa_init_upper 31 | ||
466 | .set pop | 502 | .set pop |
467 | .endm | 503 | .endm |
468 | 504 | ||
diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index dd083e999b08..b104ad9d655f 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h | |||
@@ -48,6 +48,12 @@ enum fpu_mode { | |||
48 | #define FPU_FR_MASK 0x1 | 48 | #define FPU_FR_MASK 0x1 |
49 | }; | 49 | }; |
50 | 50 | ||
51 | #define __disable_fpu() \ | ||
52 | do { \ | ||
53 | clear_c0_status(ST0_CU1); \ | ||
54 | disable_fpu_hazard(); \ | ||
55 | } while (0) | ||
56 | |||
51 | static inline int __enable_fpu(enum fpu_mode mode) | 57 | static inline int __enable_fpu(enum fpu_mode mode) |
52 | { | 58 | { |
53 | int fr; | 59 | int fr; |
@@ -86,7 +92,12 @@ fr_common: | |||
86 | enable_fpu_hazard(); | 92 | enable_fpu_hazard(); |
87 | 93 | ||
88 | /* check FR has the desired value */ | 94 | /* check FR has the desired value */ |
89 | return (!!(read_c0_status() & ST0_FR) == !!fr) ? 0 : SIGFPE; | 95 | if (!!(read_c0_status() & ST0_FR) == !!fr) |
96 | return 0; | ||
97 | |||
98 | /* unsupported FR value */ | ||
99 | __disable_fpu(); | ||
100 | return SIGFPE; | ||
90 | 101 | ||
91 | default: | 102 | default: |
92 | BUG(); | 103 | BUG(); |
@@ -95,12 +106,6 @@ fr_common: | |||
95 | return SIGFPE; | 106 | return SIGFPE; |
96 | } | 107 | } |
97 | 108 | ||
98 | #define __disable_fpu() \ | ||
99 | do { \ | ||
100 | clear_c0_status(ST0_CU1); \ | ||
101 | disable_fpu_hazard(); \ | ||
102 | } while (0) | ||
103 | |||
104 | #define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU) | 109 | #define clear_fpu_owner() clear_thread_flag(TIF_USEDFPU) |
105 | 110 | ||
106 | static inline int __is_fpu_owner(void) | 111 | static inline int __is_fpu_owner(void) |
@@ -170,6 +175,7 @@ static inline void lose_fpu(int save) | |||
170 | } | 175 | } |
171 | disable_msa(); | 176 | disable_msa(); |
172 | clear_thread_flag(TIF_USEDMSA); | 177 | clear_thread_flag(TIF_USEDMSA); |
178 | __disable_fpu(); | ||
173 | } else if (is_fpu_owner()) { | 179 | } else if (is_fpu_owner()) { |
174 | if (save) | 180 | if (save) |
175 | _save_fp(current); | 181 | _save_fp(current); |
diff --git a/arch/mips/include/asm/kdebug.h b/arch/mips/include/asm/kdebug.h index 6a9af5fcb5d7..cba22ab7ad4d 100644 --- a/arch/mips/include/asm/kdebug.h +++ b/arch/mips/include/asm/kdebug.h | |||
@@ -10,7 +10,8 @@ enum die_val { | |||
10 | DIE_RI, | 10 | DIE_RI, |
11 | DIE_PAGE_FAULT, | 11 | DIE_PAGE_FAULT, |
12 | DIE_BREAK, | 12 | DIE_BREAK, |
13 | DIE_SSTEPBP | 13 | DIE_SSTEPBP, |
14 | DIE_MSAFP | ||
14 | }; | 15 | }; |
15 | 16 | ||
16 | #endif /* _ASM_MIPS_KDEBUG_H */ | 17 | #endif /* _ASM_MIPS_KDEBUG_H */ |
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index ac4fc716062b..4c25823563fe 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h | |||
@@ -21,10 +21,10 @@ | |||
21 | 21 | ||
22 | /* MIPS KVM register ids */ | 22 | /* MIPS KVM register ids */ |
23 | #define MIPS_CP0_32(_R, _S) \ | 23 | #define MIPS_CP0_32(_R, _S) \ |
24 | (KVM_REG_MIPS | KVM_REG_SIZE_U32 | 0x10000 | (8 * (_R) + (_S))) | 24 | (KVM_REG_MIPS_CP0 | KVM_REG_SIZE_U32 | (8 * (_R) + (_S))) |
25 | 25 | ||
26 | #define MIPS_CP0_64(_R, _S) \ | 26 | #define MIPS_CP0_64(_R, _S) \ |
27 | (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 0x10000 | (8 * (_R) + (_S))) | 27 | (KVM_REG_MIPS_CP0 | KVM_REG_SIZE_U64 | (8 * (_R) + (_S))) |
28 | 28 | ||
29 | #define KVM_REG_MIPS_CP0_INDEX MIPS_CP0_32(0, 0) | 29 | #define KVM_REG_MIPS_CP0_INDEX MIPS_CP0_32(0, 0) |
30 | #define KVM_REG_MIPS_CP0_ENTRYLO0 MIPS_CP0_64(2, 0) | 30 | #define KVM_REG_MIPS_CP0_ENTRYLO0 MIPS_CP0_64(2, 0) |
@@ -42,11 +42,14 @@ | |||
42 | #define KVM_REG_MIPS_CP0_STATUS MIPS_CP0_32(12, 0) | 42 | #define KVM_REG_MIPS_CP0_STATUS MIPS_CP0_32(12, 0) |
43 | #define KVM_REG_MIPS_CP0_CAUSE MIPS_CP0_32(13, 0) | 43 | #define KVM_REG_MIPS_CP0_CAUSE MIPS_CP0_32(13, 0) |
44 | #define KVM_REG_MIPS_CP0_EPC MIPS_CP0_64(14, 0) | 44 | #define KVM_REG_MIPS_CP0_EPC MIPS_CP0_64(14, 0) |
45 | #define KVM_REG_MIPS_CP0_PRID MIPS_CP0_32(15, 0) | ||
45 | #define KVM_REG_MIPS_CP0_EBASE MIPS_CP0_64(15, 1) | 46 | #define KVM_REG_MIPS_CP0_EBASE MIPS_CP0_64(15, 1) |
46 | #define KVM_REG_MIPS_CP0_CONFIG MIPS_CP0_32(16, 0) | 47 | #define KVM_REG_MIPS_CP0_CONFIG MIPS_CP0_32(16, 0) |
47 | #define KVM_REG_MIPS_CP0_CONFIG1 MIPS_CP0_32(16, 1) | 48 | #define KVM_REG_MIPS_CP0_CONFIG1 MIPS_CP0_32(16, 1) |
48 | #define KVM_REG_MIPS_CP0_CONFIG2 MIPS_CP0_32(16, 2) | 49 | #define KVM_REG_MIPS_CP0_CONFIG2 MIPS_CP0_32(16, 2) |
49 | #define KVM_REG_MIPS_CP0_CONFIG3 MIPS_CP0_32(16, 3) | 50 | #define KVM_REG_MIPS_CP0_CONFIG3 MIPS_CP0_32(16, 3) |
51 | #define KVM_REG_MIPS_CP0_CONFIG4 MIPS_CP0_32(16, 4) | ||
52 | #define KVM_REG_MIPS_CP0_CONFIG5 MIPS_CP0_32(16, 5) | ||
50 | #define KVM_REG_MIPS_CP0_CONFIG7 MIPS_CP0_32(16, 7) | 53 | #define KVM_REG_MIPS_CP0_CONFIG7 MIPS_CP0_32(16, 7) |
51 | #define KVM_REG_MIPS_CP0_XCONTEXT MIPS_CP0_64(20, 0) | 54 | #define KVM_REG_MIPS_CP0_XCONTEXT MIPS_CP0_64(20, 0) |
52 | #define KVM_REG_MIPS_CP0_ERROREPC MIPS_CP0_64(30, 0) | 55 | #define KVM_REG_MIPS_CP0_ERROREPC MIPS_CP0_64(30, 0) |
@@ -119,6 +122,10 @@ struct kvm_vcpu_stat { | |||
119 | u32 syscall_exits; | 122 | u32 syscall_exits; |
120 | u32 resvd_inst_exits; | 123 | u32 resvd_inst_exits; |
121 | u32 break_inst_exits; | 124 | u32 break_inst_exits; |
125 | u32 trap_inst_exits; | ||
126 | u32 msa_fpe_exits; | ||
127 | u32 fpe_exits; | ||
128 | u32 msa_disabled_exits; | ||
122 | u32 flush_dcache_exits; | 129 | u32 flush_dcache_exits; |
123 | u32 halt_successful_poll; | 130 | u32 halt_successful_poll; |
124 | u32 halt_wakeup; | 131 | u32 halt_wakeup; |
@@ -138,6 +145,10 @@ enum kvm_mips_exit_types { | |||
138 | SYSCALL_EXITS, | 145 | SYSCALL_EXITS, |
139 | RESVD_INST_EXITS, | 146 | RESVD_INST_EXITS, |
140 | BREAK_INST_EXITS, | 147 | BREAK_INST_EXITS, |
148 | TRAP_INST_EXITS, | ||
149 | MSA_FPE_EXITS, | ||
150 | FPE_EXITS, | ||
151 | MSA_DISABLED_EXITS, | ||
141 | FLUSH_DCACHE_EXITS, | 152 | FLUSH_DCACHE_EXITS, |
142 | MAX_KVM_MIPS_EXIT_TYPES | 153 | MAX_KVM_MIPS_EXIT_TYPES |
143 | }; | 154 | }; |
@@ -206,6 +217,8 @@ struct mips_coproc { | |||
206 | #define MIPS_CP0_CONFIG1_SEL 1 | 217 | #define MIPS_CP0_CONFIG1_SEL 1 |
207 | #define MIPS_CP0_CONFIG2_SEL 2 | 218 | #define MIPS_CP0_CONFIG2_SEL 2 |
208 | #define MIPS_CP0_CONFIG3_SEL 3 | 219 | #define MIPS_CP0_CONFIG3_SEL 3 |
220 | #define MIPS_CP0_CONFIG4_SEL 4 | ||
221 | #define MIPS_CP0_CONFIG5_SEL 5 | ||
209 | 222 | ||
210 | /* Config0 register bits */ | 223 | /* Config0 register bits */ |
211 | #define CP0C0_M 31 | 224 | #define CP0C0_M 31 |
@@ -262,31 +275,6 @@ struct mips_coproc { | |||
262 | #define CP0C3_SM 1 | 275 | #define CP0C3_SM 1 |
263 | #define CP0C3_TL 0 | 276 | #define CP0C3_TL 0 |
264 | 277 | ||
265 | /* Have config1, Cacheable, noncoherent, write-back, write allocate*/ | ||
266 | #define MIPS_CONFIG0 \ | ||
267 | ((1 << CP0C0_M) | (0x3 << CP0C0_K0)) | ||
268 | |||
269 | /* Have config2, no coprocessor2 attached, no MDMX support attached, | ||
270 | no performance counters, watch registers present, | ||
271 | no code compression, EJTAG present, no FPU, no watch registers */ | ||
272 | #define MIPS_CONFIG1 \ | ||
273 | ((1 << CP0C1_M) | \ | ||
274 | (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \ | ||
275 | (0 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \ | ||
276 | (0 << CP0C1_FP)) | ||
277 | |||
278 | /* Have config3, no tertiary/secondary caches implemented */ | ||
279 | #define MIPS_CONFIG2 \ | ||
280 | ((1 << CP0C2_M)) | ||
281 | |||
282 | /* No config4, no DSP ASE, no large physaddr (PABITS), | ||
283 | no external interrupt controller, no vectored interrupts, | ||
284 | no 1kb pages, no SmartMIPS ASE, no trace logic */ | ||
285 | #define MIPS_CONFIG3 \ | ||
286 | ((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \ | ||
287 | (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \ | ||
288 | (0 << CP0C3_SM) | (0 << CP0C3_TL)) | ||
289 | |||
290 | /* MMU types, the first four entries have the same layout as the | 278 | /* MMU types, the first four entries have the same layout as the |
291 | CP0C0_MT field. */ | 279 | CP0C0_MT field. */ |
292 | enum mips_mmu_types { | 280 | enum mips_mmu_types { |
@@ -321,7 +309,9 @@ enum mips_mmu_types { | |||
321 | */ | 309 | */ |
322 | #define T_TRAP 13 /* Trap instruction */ | 310 | #define T_TRAP 13 /* Trap instruction */ |
323 | #define T_VCEI 14 /* Virtual coherency exception */ | 311 | #define T_VCEI 14 /* Virtual coherency exception */ |
312 | #define T_MSAFPE 14 /* MSA floating point exception */ | ||
324 | #define T_FPE 15 /* Floating point exception */ | 313 | #define T_FPE 15 /* Floating point exception */ |
314 | #define T_MSADIS 21 /* MSA disabled exception */ | ||
325 | #define T_WATCH 23 /* Watch address reference */ | 315 | #define T_WATCH 23 /* Watch address reference */ |
326 | #define T_VCED 31 /* Virtual coherency data */ | 316 | #define T_VCED 31 /* Virtual coherency data */ |
327 | 317 | ||
@@ -374,6 +364,9 @@ struct kvm_mips_tlb { | |||
374 | long tlb_lo1; | 364 | long tlb_lo1; |
375 | }; | 365 | }; |
376 | 366 | ||
367 | #define KVM_MIPS_FPU_FPU 0x1 | ||
368 | #define KVM_MIPS_FPU_MSA 0x2 | ||
369 | |||
377 | #define KVM_MIPS_GUEST_TLB_SIZE 64 | 370 | #define KVM_MIPS_GUEST_TLB_SIZE 64 |
378 | struct kvm_vcpu_arch { | 371 | struct kvm_vcpu_arch { |
379 | void *host_ebase, *guest_ebase; | 372 | void *host_ebase, *guest_ebase; |
@@ -395,6 +388,8 @@ struct kvm_vcpu_arch { | |||
395 | 388 | ||
396 | /* FPU State */ | 389 | /* FPU State */ |
397 | struct mips_fpu_struct fpu; | 390 | struct mips_fpu_struct fpu; |
391 | /* Which FPU state is loaded (KVM_MIPS_FPU_*) */ | ||
392 | unsigned int fpu_inuse; | ||
398 | 393 | ||
399 | /* COP0 State */ | 394 | /* COP0 State */ |
400 | struct mips_coproc *cop0; | 395 | struct mips_coproc *cop0; |
@@ -441,6 +436,9 @@ struct kvm_vcpu_arch { | |||
441 | 436 | ||
442 | /* WAIT executed */ | 437 | /* WAIT executed */ |
443 | int wait; | 438 | int wait; |
439 | |||
440 | u8 fpu_enabled; | ||
441 | u8 msa_enabled; | ||
444 | }; | 442 | }; |
445 | 443 | ||
446 | 444 | ||
@@ -482,11 +480,15 @@ struct kvm_vcpu_arch { | |||
482 | #define kvm_read_c0_guest_config1(cop0) (cop0->reg[MIPS_CP0_CONFIG][1]) | 480 | #define kvm_read_c0_guest_config1(cop0) (cop0->reg[MIPS_CP0_CONFIG][1]) |
483 | #define kvm_read_c0_guest_config2(cop0) (cop0->reg[MIPS_CP0_CONFIG][2]) | 481 | #define kvm_read_c0_guest_config2(cop0) (cop0->reg[MIPS_CP0_CONFIG][2]) |
484 | #define kvm_read_c0_guest_config3(cop0) (cop0->reg[MIPS_CP0_CONFIG][3]) | 482 | #define kvm_read_c0_guest_config3(cop0) (cop0->reg[MIPS_CP0_CONFIG][3]) |
483 | #define kvm_read_c0_guest_config4(cop0) (cop0->reg[MIPS_CP0_CONFIG][4]) | ||
484 | #define kvm_read_c0_guest_config5(cop0) (cop0->reg[MIPS_CP0_CONFIG][5]) | ||
485 | #define kvm_read_c0_guest_config7(cop0) (cop0->reg[MIPS_CP0_CONFIG][7]) | 485 | #define kvm_read_c0_guest_config7(cop0) (cop0->reg[MIPS_CP0_CONFIG][7]) |
486 | #define kvm_write_c0_guest_config(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][0] = (val)) | 486 | #define kvm_write_c0_guest_config(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][0] = (val)) |
487 | #define kvm_write_c0_guest_config1(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][1] = (val)) | 487 | #define kvm_write_c0_guest_config1(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][1] = (val)) |
488 | #define kvm_write_c0_guest_config2(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][2] = (val)) | 488 | #define kvm_write_c0_guest_config2(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][2] = (val)) |
489 | #define kvm_write_c0_guest_config3(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][3] = (val)) | 489 | #define kvm_write_c0_guest_config3(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][3] = (val)) |
490 | #define kvm_write_c0_guest_config4(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][4] = (val)) | ||
491 | #define kvm_write_c0_guest_config5(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][5] = (val)) | ||
490 | #define kvm_write_c0_guest_config7(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][7] = (val)) | 492 | #define kvm_write_c0_guest_config7(cop0, val) (cop0->reg[MIPS_CP0_CONFIG][7] = (val)) |
491 | #define kvm_read_c0_guest_errorepc(cop0) (cop0->reg[MIPS_CP0_ERROR_PC][0]) | 493 | #define kvm_read_c0_guest_errorepc(cop0) (cop0->reg[MIPS_CP0_ERROR_PC][0]) |
492 | #define kvm_write_c0_guest_errorepc(cop0, val) (cop0->reg[MIPS_CP0_ERROR_PC][0] = (val)) | 494 | #define kvm_write_c0_guest_errorepc(cop0, val) (cop0->reg[MIPS_CP0_ERROR_PC][0] = (val)) |
@@ -567,6 +569,31 @@ static inline void _kvm_atomic_change_c0_guest_reg(unsigned long *reg, | |||
567 | kvm_set_c0_guest_ebase(cop0, ((val) & (change))); \ | 569 | kvm_set_c0_guest_ebase(cop0, ((val) & (change))); \ |
568 | } | 570 | } |
569 | 571 | ||
572 | /* Helpers */ | ||
573 | |||
574 | static inline bool kvm_mips_guest_can_have_fpu(struct kvm_vcpu_arch *vcpu) | ||
575 | { | ||
576 | return (!__builtin_constant_p(cpu_has_fpu) || cpu_has_fpu) && | ||
577 | vcpu->fpu_enabled; | ||
578 | } | ||
579 | |||
580 | static inline bool kvm_mips_guest_has_fpu(struct kvm_vcpu_arch *vcpu) | ||
581 | { | ||
582 | return kvm_mips_guest_can_have_fpu(vcpu) && | ||
583 | kvm_read_c0_guest_config1(vcpu->cop0) & MIPS_CONF1_FP; | ||
584 | } | ||
585 | |||
586 | static inline bool kvm_mips_guest_can_have_msa(struct kvm_vcpu_arch *vcpu) | ||
587 | { | ||
588 | return (!__builtin_constant_p(cpu_has_msa) || cpu_has_msa) && | ||
589 | vcpu->msa_enabled; | ||
590 | } | ||
591 | |||
592 | static inline bool kvm_mips_guest_has_msa(struct kvm_vcpu_arch *vcpu) | ||
593 | { | ||
594 | return kvm_mips_guest_can_have_msa(vcpu) && | ||
595 | kvm_read_c0_guest_config3(vcpu->cop0) & MIPS_CONF3_MSA; | ||
596 | } | ||
570 | 597 | ||
571 | struct kvm_mips_callbacks { | 598 | struct kvm_mips_callbacks { |
572 | int (*handle_cop_unusable)(struct kvm_vcpu *vcpu); | 599 | int (*handle_cop_unusable)(struct kvm_vcpu *vcpu); |
@@ -578,6 +605,10 @@ struct kvm_mips_callbacks { | |||
578 | int (*handle_syscall)(struct kvm_vcpu *vcpu); | 605 | int (*handle_syscall)(struct kvm_vcpu *vcpu); |
579 | int (*handle_res_inst)(struct kvm_vcpu *vcpu); | 606 | int (*handle_res_inst)(struct kvm_vcpu *vcpu); |
580 | int (*handle_break)(struct kvm_vcpu *vcpu); | 607 | int (*handle_break)(struct kvm_vcpu *vcpu); |
608 | int (*handle_trap)(struct kvm_vcpu *vcpu); | ||
609 | int (*handle_msa_fpe)(struct kvm_vcpu *vcpu); | ||
610 | int (*handle_fpe)(struct kvm_vcpu *vcpu); | ||
611 | int (*handle_msa_disabled)(struct kvm_vcpu *vcpu); | ||
581 | int (*vm_init)(struct kvm *kvm); | 612 | int (*vm_init)(struct kvm *kvm); |
582 | int (*vcpu_init)(struct kvm_vcpu *vcpu); | 613 | int (*vcpu_init)(struct kvm_vcpu *vcpu); |
583 | int (*vcpu_setup)(struct kvm_vcpu *vcpu); | 614 | int (*vcpu_setup)(struct kvm_vcpu *vcpu); |
@@ -596,6 +627,8 @@ struct kvm_mips_callbacks { | |||
596 | const struct kvm_one_reg *reg, s64 *v); | 627 | const struct kvm_one_reg *reg, s64 *v); |
597 | int (*set_one_reg)(struct kvm_vcpu *vcpu, | 628 | int (*set_one_reg)(struct kvm_vcpu *vcpu, |
598 | const struct kvm_one_reg *reg, s64 v); | 629 | const struct kvm_one_reg *reg, s64 v); |
630 | int (*vcpu_get_regs)(struct kvm_vcpu *vcpu); | ||
631 | int (*vcpu_set_regs)(struct kvm_vcpu *vcpu); | ||
599 | }; | 632 | }; |
600 | extern struct kvm_mips_callbacks *kvm_mips_callbacks; | 633 | extern struct kvm_mips_callbacks *kvm_mips_callbacks; |
601 | int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks); | 634 | int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks); |
@@ -606,6 +639,19 @@ int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu); | |||
606 | /* Trampoline ASM routine to start running in "Guest" context */ | 639 | /* Trampoline ASM routine to start running in "Guest" context */ |
607 | extern int __kvm_mips_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu); | 640 | extern int __kvm_mips_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu); |
608 | 641 | ||
642 | /* FPU/MSA context management */ | ||
643 | void __kvm_save_fpu(struct kvm_vcpu_arch *vcpu); | ||
644 | void __kvm_restore_fpu(struct kvm_vcpu_arch *vcpu); | ||
645 | void __kvm_restore_fcsr(struct kvm_vcpu_arch *vcpu); | ||
646 | void __kvm_save_msa(struct kvm_vcpu_arch *vcpu); | ||
647 | void __kvm_restore_msa(struct kvm_vcpu_arch *vcpu); | ||
648 | void __kvm_restore_msa_upper(struct kvm_vcpu_arch *vcpu); | ||
649 | void __kvm_restore_msacsr(struct kvm_vcpu_arch *vcpu); | ||
650 | void kvm_own_fpu(struct kvm_vcpu *vcpu); | ||
651 | void kvm_own_msa(struct kvm_vcpu *vcpu); | ||
652 | void kvm_drop_fpu(struct kvm_vcpu *vcpu); | ||
653 | void kvm_lose_fpu(struct kvm_vcpu *vcpu); | ||
654 | |||
609 | /* TLB handling */ | 655 | /* TLB handling */ |
610 | uint32_t kvm_get_kernel_asid(struct kvm_vcpu *vcpu); | 656 | uint32_t kvm_get_kernel_asid(struct kvm_vcpu *vcpu); |
611 | 657 | ||
@@ -711,6 +757,26 @@ extern enum emulation_result kvm_mips_emulate_bp_exc(unsigned long cause, | |||
711 | struct kvm_run *run, | 757 | struct kvm_run *run, |
712 | struct kvm_vcpu *vcpu); | 758 | struct kvm_vcpu *vcpu); |
713 | 759 | ||
760 | extern enum emulation_result kvm_mips_emulate_trap_exc(unsigned long cause, | ||
761 | uint32_t *opc, | ||
762 | struct kvm_run *run, | ||
763 | struct kvm_vcpu *vcpu); | ||
764 | |||
765 | extern enum emulation_result kvm_mips_emulate_msafpe_exc(unsigned long cause, | ||
766 | uint32_t *opc, | ||
767 | struct kvm_run *run, | ||
768 | struct kvm_vcpu *vcpu); | ||
769 | |||
770 | extern enum emulation_result kvm_mips_emulate_fpe_exc(unsigned long cause, | ||
771 | uint32_t *opc, | ||
772 | struct kvm_run *run, | ||
773 | struct kvm_vcpu *vcpu); | ||
774 | |||
775 | extern enum emulation_result kvm_mips_emulate_msadis_exc(unsigned long cause, | ||
776 | uint32_t *opc, | ||
777 | struct kvm_run *run, | ||
778 | struct kvm_vcpu *vcpu); | ||
779 | |||
714 | extern enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, | 780 | extern enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, |
715 | struct kvm_run *run); | 781 | struct kvm_run *run); |
716 | 782 | ||
@@ -749,6 +815,11 @@ enum emulation_result kvm_mips_emulate_load(uint32_t inst, | |||
749 | struct kvm_run *run, | 815 | struct kvm_run *run, |
750 | struct kvm_vcpu *vcpu); | 816 | struct kvm_vcpu *vcpu); |
751 | 817 | ||
818 | unsigned int kvm_mips_config1_wrmask(struct kvm_vcpu *vcpu); | ||
819 | unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu); | ||
820 | unsigned int kvm_mips_config4_wrmask(struct kvm_vcpu *vcpu); | ||
821 | unsigned int kvm_mips_config5_wrmask(struct kvm_vcpu *vcpu); | ||
822 | |||
752 | /* Dynamic binary translation */ | 823 | /* Dynamic binary translation */ |
753 | extern int kvm_mips_trans_cache_index(uint32_t inst, uint32_t *opc, | 824 | extern int kvm_mips_trans_cache_index(uint32_t inst, uint32_t *opc, |
754 | struct kvm_vcpu *vcpu); | 825 | struct kvm_vcpu *vcpu); |
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index b5dcbee01fd7..9b3b48e21c22 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h | |||
@@ -105,7 +105,7 @@ union fpureg { | |||
105 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | 105 | #ifdef CONFIG_CPU_LITTLE_ENDIAN |
106 | # define FPR_IDX(width, idx) (idx) | 106 | # define FPR_IDX(width, idx) (idx) |
107 | #else | 107 | #else |
108 | # define FPR_IDX(width, idx) ((FPU_REG_WIDTH / (width)) - 1 - (idx)) | 108 | # define FPR_IDX(width, idx) ((idx) ^ ((64 / (width)) - 1)) |
109 | #endif | 109 | #endif |
110 | 110 | ||
111 | #define BUILD_FPR_ACCESS(width) \ | 111 | #define BUILD_FPR_ACCESS(width) \ |
diff --git a/arch/mips/include/uapi/asm/kvm.h b/arch/mips/include/uapi/asm/kvm.h index 2c04b6d9ff85..6985eb59b085 100644 --- a/arch/mips/include/uapi/asm/kvm.h +++ b/arch/mips/include/uapi/asm/kvm.h | |||
@@ -36,77 +36,85 @@ 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 | */ |
43 | struct kvm_fpu { | 40 | struct 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 | ||
54 | /* | 44 | /* |
55 | * For MIPS, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access CP0 | 45 | * For MIPS, we use KVM_SET_ONE_REG and KVM_GET_ONE_REG to access various |
56 | * registers. The id field is broken down as follows: | 46 | * registers. The id field is broken down as follows: |
57 | * | 47 | * |
58 | * bits[2..0] - Register 'sel' index. | ||
59 | * bits[7..3] - Register 'rd' index. | ||
60 | * bits[15..8] - Must be zero. | ||
61 | * bits[31..16] - 1 -> CP0 registers. | ||
62 | * bits[51..32] - Must be zero. | ||
63 | * bits[63..52] - As per linux/kvm.h | 48 | * bits[63..52] - As per linux/kvm.h |
49 | * bits[51..32] - Must be zero. | ||
50 | * bits[31..16] - Register set. | ||
51 | * | ||
52 | * Register set = 0: GP registers from kvm_regs (see definitions below). | ||
53 | * | ||
54 | * Register set = 1: CP0 registers. | ||
55 | * bits[15..8] - Must be zero. | ||
56 | * bits[7..3] - Register 'rd' index. | ||
57 | * bits[2..0] - Register 'sel' index. | ||
58 | * | ||
59 | * Register set = 2: KVM specific registers (see definitions below). | ||
60 | * | ||
61 | * Register set = 3: FPU / MSA registers (see definitions below). | ||
64 | * | 62 | * |
65 | * 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 |
66 | * have its own identifier in bits[31..16]. | 64 | * have its own identifier in bits[31..16]. |
67 | * | ||
68 | * The registers defined in struct kvm_regs are also accessible, the | ||
69 | * id values for these are below. | ||
70 | */ | 65 | */ |
71 | 66 | ||
72 | #define KVM_REG_MIPS_R0 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 0) | 67 | #define KVM_REG_MIPS_GP (KVM_REG_MIPS | 0x0000000000000000ULL) |
73 | #define KVM_REG_MIPS_R1 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 1) | 68 | #define KVM_REG_MIPS_CP0 (KVM_REG_MIPS | 0x0000000000010000ULL) |
74 | #define KVM_REG_MIPS_R2 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 2) | 69 | #define KVM_REG_MIPS_KVM (KVM_REG_MIPS | 0x0000000000020000ULL) |
75 | #define KVM_REG_MIPS_R3 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 3) | 70 | #define KVM_REG_MIPS_FPU (KVM_REG_MIPS | 0x0000000000030000ULL) |
76 | #define KVM_REG_MIPS_R4 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 4) | 71 | |
77 | #define KVM_REG_MIPS_R5 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 5) | 72 | |
78 | #define KVM_REG_MIPS_R6 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 6) | 73 | /* |
79 | #define KVM_REG_MIPS_R7 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 7) | 74 | * KVM_REG_MIPS_GP - General purpose registers from kvm_regs. |
80 | #define KVM_REG_MIPS_R8 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 8) | 75 | */ |
81 | #define KVM_REG_MIPS_R9 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 9) | 76 | |
82 | #define KVM_REG_MIPS_R10 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 10) | 77 | #define KVM_REG_MIPS_R0 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 0) |
83 | #define KVM_REG_MIPS_R11 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 11) | 78 | #define KVM_REG_MIPS_R1 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 1) |
84 | #define KVM_REG_MIPS_R12 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 12) | 79 | #define KVM_REG_MIPS_R2 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 2) |
85 | #define KVM_REG_MIPS_R13 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 13) | 80 | #define KVM_REG_MIPS_R3 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 3) |
86 | #define KVM_REG_MIPS_R14 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 14) | 81 | #define KVM_REG_MIPS_R4 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 4) |
87 | #define KVM_REG_MIPS_R15 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 15) | 82 | #define KVM_REG_MIPS_R5 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 5) |
88 | #define KVM_REG_MIPS_R16 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 16) | 83 | #define KVM_REG_MIPS_R6 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 6) |
89 | #define KVM_REG_MIPS_R17 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 17) | 84 | #define KVM_REG_MIPS_R7 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 7) |
90 | #define KVM_REG_MIPS_R18 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 18) | 85 | #define KVM_REG_MIPS_R8 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 8) |
91 | #define KVM_REG_MIPS_R19 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 19) | 86 | #define KVM_REG_MIPS_R9 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 9) |
92 | #define KVM_REG_MIPS_R20 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 20) | 87 | #define KVM_REG_MIPS_R10 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 10) |
93 | #define KVM_REG_MIPS_R21 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 21) | 88 | #define KVM_REG_MIPS_R11 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 11) |
94 | #define KVM_REG_MIPS_R22 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 22) | 89 | #define KVM_REG_MIPS_R12 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 12) |
95 | #define KVM_REG_MIPS_R23 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 23) | 90 | #define KVM_REG_MIPS_R13 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 13) |
96 | #define KVM_REG_MIPS_R24 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 24) | 91 | #define KVM_REG_MIPS_R14 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 14) |
97 | #define KVM_REG_MIPS_R25 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 25) | 92 | #define KVM_REG_MIPS_R15 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 15) |
98 | #define KVM_REG_MIPS_R26 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 26) | 93 | #define KVM_REG_MIPS_R16 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 16) |
99 | #define KVM_REG_MIPS_R27 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 27) | 94 | #define KVM_REG_MIPS_R17 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 17) |
100 | #define KVM_REG_MIPS_R28 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 28) | 95 | #define KVM_REG_MIPS_R18 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 18) |
101 | #define KVM_REG_MIPS_R29 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 29) | 96 | #define KVM_REG_MIPS_R19 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 19) |
102 | #define KVM_REG_MIPS_R30 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 30) | 97 | #define KVM_REG_MIPS_R20 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 20) |
103 | #define KVM_REG_MIPS_R31 (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 31) | 98 | #define KVM_REG_MIPS_R21 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 21) |
104 | 99 | #define KVM_REG_MIPS_R22 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 22) | |
105 | #define KVM_REG_MIPS_HI (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 32) | 100 | #define KVM_REG_MIPS_R23 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 23) |
106 | #define KVM_REG_MIPS_LO (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 33) | 101 | #define KVM_REG_MIPS_R24 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 24) |
107 | #define KVM_REG_MIPS_PC (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 34) | 102 | #define KVM_REG_MIPS_R25 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 25) |
108 | 103 | #define KVM_REG_MIPS_R26 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 26) | |
109 | /* KVM specific control registers */ | 104 | #define KVM_REG_MIPS_R27 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 27) |
105 | #define KVM_REG_MIPS_R28 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 28) | ||
106 | #define KVM_REG_MIPS_R29 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 29) | ||
107 | #define KVM_REG_MIPS_R30 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 30) | ||
108 | #define KVM_REG_MIPS_R31 (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 31) | ||
109 | |||
110 | #define KVM_REG_MIPS_HI (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 32) | ||
111 | #define KVM_REG_MIPS_LO (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 33) | ||
112 | #define KVM_REG_MIPS_PC (KVM_REG_MIPS_GP | KVM_REG_SIZE_U64 | 34) | ||
113 | |||
114 | |||
115 | /* | ||
116 | * KVM_REG_MIPS_KVM - KVM specific control registers. | ||
117 | */ | ||
110 | 118 | ||
111 | /* | 119 | /* |
112 | * CP0_Count control | 120 | * CP0_Count control |
@@ -118,8 +126,7 @@ struct kvm_fpu { | |||
118 | * safely without losing time or guest timer interrupts. | 126 | * safely without losing time or guest timer interrupts. |
119 | * Other: Reserved, do not change. | 127 | * Other: Reserved, do not change. |
120 | */ | 128 | */ |
121 | #define KVM_REG_MIPS_COUNT_CTL (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ | 129 | #define KVM_REG_MIPS_COUNT_CTL (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 0) |
122 | 0x20000 | 0) | ||
123 | #define KVM_REG_MIPS_COUNT_CTL_DC 0x00000001 | 130 | #define KVM_REG_MIPS_COUNT_CTL_DC 0x00000001 |
124 | 131 | ||
125 | /* | 132 | /* |
@@ -131,15 +138,46 @@ struct kvm_fpu { | |||
131 | * emulated. | 138 | * emulated. |
132 | * Modifications to times in the future are rejected. | 139 | * Modifications to times in the future are rejected. |
133 | */ | 140 | */ |
134 | #define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ | 141 | #define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 1) |
135 | 0x20000 | 1) | ||
136 | /* | 142 | /* |
137 | * CP0_Count rate in Hz | 143 | * CP0_Count rate in Hz |
138 | * Specifies the rate of the CP0_Count timer in Hz. Modifications occur without | 144 | * Specifies the rate of the CP0_Count timer in Hz. Modifications occur without |
139 | * discontinuities in CP0_Count. | 145 | * discontinuities in CP0_Count. |
140 | */ | 146 | */ |
141 | #define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ | 147 | #define KVM_REG_MIPS_COUNT_HZ (KVM_REG_MIPS_KVM | KVM_REG_SIZE_U64 | 2) |
142 | 0x20000 | 2) | 148 | |
149 | |||
150 | /* | ||
151 | * KVM_REG_MIPS_FPU - Floating Point and MIPS SIMD Architecture (MSA) 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 | #define KVM_REG_MIPS_MSACR (KVM_REG_MIPS_FPU | 0x0000000000000200ULL) | ||
161 | |||
162 | /* | ||
163 | * KVM_REG_MIPS_FPR - Floating point / Vector registers. | ||
164 | */ | ||
165 | #define KVM_REG_MIPS_FPR_32(n) (KVM_REG_MIPS_FPR | KVM_REG_SIZE_U32 | (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)) | ||
168 | |||
169 | /* | ||
170 | * KVM_REG_MIPS_FCR - Floating point control registers. | ||
171 | */ | ||
172 | #define KVM_REG_MIPS_FCR_IR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 0) | ||
173 | #define KVM_REG_MIPS_FCR_CSR (KVM_REG_MIPS_FCR | KVM_REG_SIZE_U32 | 31) | ||
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 | |||
143 | 181 | ||
144 | /* | 182 | /* |
145 | * KVM MIPS specific structures and definitions | 183 | * KVM MIPS specific structures and definitions |
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 750d67ac41e9..e59fd7cfac9e 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c | |||
@@ -167,72 +167,6 @@ void output_thread_fpu_defines(void) | |||
167 | OFFSET(THREAD_FPR30, task_struct, thread.fpu.fpr[30]); | 167 | OFFSET(THREAD_FPR30, task_struct, thread.fpu.fpr[30]); |
168 | OFFSET(THREAD_FPR31, task_struct, thread.fpu.fpr[31]); | 168 | OFFSET(THREAD_FPR31, task_struct, thread.fpu.fpr[31]); |
169 | 169 | ||
170 | /* the least significant 64 bits of each FP register */ | ||
171 | OFFSET(THREAD_FPR0_LS64, task_struct, | ||
172 | thread.fpu.fpr[0].val64[FPR_IDX(64, 0)]); | ||
173 | OFFSET(THREAD_FPR1_LS64, task_struct, | ||
174 | thread.fpu.fpr[1].val64[FPR_IDX(64, 0)]); | ||
175 | OFFSET(THREAD_FPR2_LS64, task_struct, | ||
176 | thread.fpu.fpr[2].val64[FPR_IDX(64, 0)]); | ||
177 | OFFSET(THREAD_FPR3_LS64, task_struct, | ||
178 | thread.fpu.fpr[3].val64[FPR_IDX(64, 0)]); | ||
179 | OFFSET(THREAD_FPR4_LS64, task_struct, | ||
180 | thread.fpu.fpr[4].val64[FPR_IDX(64, 0)]); | ||
181 | OFFSET(THREAD_FPR5_LS64, task_struct, | ||
182 | thread.fpu.fpr[5].val64[FPR_IDX(64, 0)]); | ||
183 | OFFSET(THREAD_FPR6_LS64, task_struct, | ||
184 | thread.fpu.fpr[6].val64[FPR_IDX(64, 0)]); | ||
185 | OFFSET(THREAD_FPR7_LS64, task_struct, | ||
186 | thread.fpu.fpr[7].val64[FPR_IDX(64, 0)]); | ||
187 | OFFSET(THREAD_FPR8_LS64, task_struct, | ||
188 | thread.fpu.fpr[8].val64[FPR_IDX(64, 0)]); | ||
189 | OFFSET(THREAD_FPR9_LS64, task_struct, | ||
190 | thread.fpu.fpr[9].val64[FPR_IDX(64, 0)]); | ||
191 | OFFSET(THREAD_FPR10_LS64, task_struct, | ||
192 | thread.fpu.fpr[10].val64[FPR_IDX(64, 0)]); | ||
193 | OFFSET(THREAD_FPR11_LS64, task_struct, | ||
194 | thread.fpu.fpr[11].val64[FPR_IDX(64, 0)]); | ||
195 | OFFSET(THREAD_FPR12_LS64, task_struct, | ||
196 | thread.fpu.fpr[12].val64[FPR_IDX(64, 0)]); | ||
197 | OFFSET(THREAD_FPR13_LS64, task_struct, | ||
198 | thread.fpu.fpr[13].val64[FPR_IDX(64, 0)]); | ||
199 | OFFSET(THREAD_FPR14_LS64, task_struct, | ||
200 | thread.fpu.fpr[14].val64[FPR_IDX(64, 0)]); | ||
201 | OFFSET(THREAD_FPR15_LS64, task_struct, | ||
202 | thread.fpu.fpr[15].val64[FPR_IDX(64, 0)]); | ||
203 | OFFSET(THREAD_FPR16_LS64, task_struct, | ||
204 | thread.fpu.fpr[16].val64[FPR_IDX(64, 0)]); | ||
205 | OFFSET(THREAD_FPR17_LS64, task_struct, | ||
206 | thread.fpu.fpr[17].val64[FPR_IDX(64, 0)]); | ||
207 | OFFSET(THREAD_FPR18_LS64, task_struct, | ||
208 | thread.fpu.fpr[18].val64[FPR_IDX(64, 0)]); | ||
209 | OFFSET(THREAD_FPR19_LS64, task_struct, | ||
210 | thread.fpu.fpr[19].val64[FPR_IDX(64, 0)]); | ||
211 | OFFSET(THREAD_FPR20_LS64, task_struct, | ||
212 | thread.fpu.fpr[20].val64[FPR_IDX(64, 0)]); | ||
213 | OFFSET(THREAD_FPR21_LS64, task_struct, | ||
214 | thread.fpu.fpr[21].val64[FPR_IDX(64, 0)]); | ||
215 | OFFSET(THREAD_FPR22_LS64, task_struct, | ||
216 | thread.fpu.fpr[22].val64[FPR_IDX(64, 0)]); | ||
217 | OFFSET(THREAD_FPR23_LS64, task_struct, | ||
218 | thread.fpu.fpr[23].val64[FPR_IDX(64, 0)]); | ||
219 | OFFSET(THREAD_FPR24_LS64, task_struct, | ||
220 | thread.fpu.fpr[24].val64[FPR_IDX(64, 0)]); | ||
221 | OFFSET(THREAD_FPR25_LS64, task_struct, | ||
222 | thread.fpu.fpr[25].val64[FPR_IDX(64, 0)]); | ||
223 | OFFSET(THREAD_FPR26_LS64, task_struct, | ||
224 | thread.fpu.fpr[26].val64[FPR_IDX(64, 0)]); | ||
225 | OFFSET(THREAD_FPR27_LS64, task_struct, | ||
226 | thread.fpu.fpr[27].val64[FPR_IDX(64, 0)]); | ||
227 | OFFSET(THREAD_FPR28_LS64, task_struct, | ||
228 | thread.fpu.fpr[28].val64[FPR_IDX(64, 0)]); | ||
229 | OFFSET(THREAD_FPR29_LS64, task_struct, | ||
230 | thread.fpu.fpr[29].val64[FPR_IDX(64, 0)]); | ||
231 | OFFSET(THREAD_FPR30_LS64, task_struct, | ||
232 | thread.fpu.fpr[30].val64[FPR_IDX(64, 0)]); | ||
233 | OFFSET(THREAD_FPR31_LS64, task_struct, | ||
234 | thread.fpu.fpr[31].val64[FPR_IDX(64, 0)]); | ||
235 | |||
236 | OFFSET(THREAD_FCR31, task_struct, thread.fpu.fcr31); | 170 | OFFSET(THREAD_FCR31, task_struct, thread.fpu.fcr31); |
237 | OFFSET(THREAD_MSA_CSR, task_struct, thread.fpu.msacsr); | 171 | OFFSET(THREAD_MSA_CSR, task_struct, thread.fpu.msacsr); |
238 | BLANK(); | 172 | BLANK(); |
@@ -470,6 +404,45 @@ void output_kvm_defines(void) | |||
470 | OFFSET(VCPU_LO, kvm_vcpu_arch, lo); | 404 | OFFSET(VCPU_LO, kvm_vcpu_arch, lo); |
471 | OFFSET(VCPU_HI, kvm_vcpu_arch, hi); | 405 | OFFSET(VCPU_HI, kvm_vcpu_arch, hi); |
472 | OFFSET(VCPU_PC, kvm_vcpu_arch, pc); | 406 | OFFSET(VCPU_PC, kvm_vcpu_arch, pc); |
407 | BLANK(); | ||
408 | |||
409 | OFFSET(VCPU_FPR0, kvm_vcpu_arch, fpu.fpr[0]); | ||
410 | OFFSET(VCPU_FPR1, kvm_vcpu_arch, fpu.fpr[1]); | ||
411 | OFFSET(VCPU_FPR2, kvm_vcpu_arch, fpu.fpr[2]); | ||
412 | OFFSET(VCPU_FPR3, kvm_vcpu_arch, fpu.fpr[3]); | ||
413 | OFFSET(VCPU_FPR4, kvm_vcpu_arch, fpu.fpr[4]); | ||
414 | OFFSET(VCPU_FPR5, kvm_vcpu_arch, fpu.fpr[5]); | ||
415 | OFFSET(VCPU_FPR6, kvm_vcpu_arch, fpu.fpr[6]); | ||
416 | OFFSET(VCPU_FPR7, kvm_vcpu_arch, fpu.fpr[7]); | ||
417 | OFFSET(VCPU_FPR8, kvm_vcpu_arch, fpu.fpr[8]); | ||
418 | OFFSET(VCPU_FPR9, kvm_vcpu_arch, fpu.fpr[9]); | ||
419 | OFFSET(VCPU_FPR10, kvm_vcpu_arch, fpu.fpr[10]); | ||
420 | OFFSET(VCPU_FPR11, kvm_vcpu_arch, fpu.fpr[11]); | ||
421 | OFFSET(VCPU_FPR12, kvm_vcpu_arch, fpu.fpr[12]); | ||
422 | OFFSET(VCPU_FPR13, kvm_vcpu_arch, fpu.fpr[13]); | ||
423 | OFFSET(VCPU_FPR14, kvm_vcpu_arch, fpu.fpr[14]); | ||
424 | OFFSET(VCPU_FPR15, kvm_vcpu_arch, fpu.fpr[15]); | ||
425 | OFFSET(VCPU_FPR16, kvm_vcpu_arch, fpu.fpr[16]); | ||
426 | OFFSET(VCPU_FPR17, kvm_vcpu_arch, fpu.fpr[17]); | ||
427 | OFFSET(VCPU_FPR18, kvm_vcpu_arch, fpu.fpr[18]); | ||
428 | OFFSET(VCPU_FPR19, kvm_vcpu_arch, fpu.fpr[19]); | ||
429 | OFFSET(VCPU_FPR20, kvm_vcpu_arch, fpu.fpr[20]); | ||
430 | OFFSET(VCPU_FPR21, kvm_vcpu_arch, fpu.fpr[21]); | ||
431 | OFFSET(VCPU_FPR22, kvm_vcpu_arch, fpu.fpr[22]); | ||
432 | OFFSET(VCPU_FPR23, kvm_vcpu_arch, fpu.fpr[23]); | ||
433 | OFFSET(VCPU_FPR24, kvm_vcpu_arch, fpu.fpr[24]); | ||
434 | OFFSET(VCPU_FPR25, kvm_vcpu_arch, fpu.fpr[25]); | ||
435 | OFFSET(VCPU_FPR26, kvm_vcpu_arch, fpu.fpr[26]); | ||
436 | OFFSET(VCPU_FPR27, kvm_vcpu_arch, fpu.fpr[27]); | ||
437 | OFFSET(VCPU_FPR28, kvm_vcpu_arch, fpu.fpr[28]); | ||
438 | OFFSET(VCPU_FPR29, kvm_vcpu_arch, fpu.fpr[29]); | ||
439 | OFFSET(VCPU_FPR30, kvm_vcpu_arch, fpu.fpr[30]); | ||
440 | OFFSET(VCPU_FPR31, kvm_vcpu_arch, fpu.fpr[31]); | ||
441 | |||
442 | OFFSET(VCPU_FCR31, kvm_vcpu_arch, fpu.fcr31); | ||
443 | OFFSET(VCPU_MSA_CSR, kvm_vcpu_arch, fpu.msacsr); | ||
444 | BLANK(); | ||
445 | |||
473 | OFFSET(VCPU_COP0, kvm_vcpu_arch, cop0); | 446 | OFFSET(VCPU_COP0, kvm_vcpu_arch, cop0); |
474 | OFFSET(VCPU_GUEST_KERNEL_ASID, kvm_vcpu_arch, guest_kernel_asid); | 447 | OFFSET(VCPU_GUEST_KERNEL_ASID, kvm_vcpu_arch, guest_kernel_asid); |
475 | OFFSET(VCPU_GUEST_USER_ASID, kvm_vcpu_arch, guest_user_asid); | 448 | OFFSET(VCPU_GUEST_USER_ASID, kvm_vcpu_arch, guest_user_asid); |
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index 2ebaabe3af15..af42e7003f12 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S | |||
@@ -360,12 +360,15 @@ NESTED(nmi_handler, PT_SIZE, sp) | |||
360 | .set mips1 | 360 | .set mips1 |
361 | SET_HARDFLOAT | 361 | SET_HARDFLOAT |
362 | cfc1 a1, fcr31 | 362 | cfc1 a1, fcr31 |
363 | li a2, ~(0x3f << 12) | ||
364 | and a2, a1 | ||
365 | ctc1 a2, fcr31 | ||
366 | .set pop | 363 | .set pop |
367 | TRACE_IRQS_ON | 364 | CLI |
368 | STI | 365 | TRACE_IRQS_OFF |
366 | .endm | ||
367 | |||
368 | .macro __build_clear_msa_fpe | ||
369 | _cfcmsa a1, MSA_CSR | ||
370 | CLI | ||
371 | TRACE_IRQS_OFF | ||
369 | .endm | 372 | .endm |
370 | 373 | ||
371 | .macro __build_clear_ade | 374 | .macro __build_clear_ade |
@@ -426,7 +429,7 @@ NESTED(nmi_handler, PT_SIZE, sp) | |||
426 | BUILD_HANDLER cpu cpu sti silent /* #11 */ | 429 | BUILD_HANDLER cpu cpu sti silent /* #11 */ |
427 | BUILD_HANDLER ov ov sti silent /* #12 */ | 430 | BUILD_HANDLER ov ov sti silent /* #12 */ |
428 | BUILD_HANDLER tr tr sti silent /* #13 */ | 431 | BUILD_HANDLER tr tr sti silent /* #13 */ |
429 | BUILD_HANDLER msa_fpe msa_fpe sti silent /* #14 */ | 432 | BUILD_HANDLER msa_fpe msa_fpe msa_fpe silent /* #14 */ |
430 | BUILD_HANDLER fpe fpe fpe silent /* #15 */ | 433 | BUILD_HANDLER fpe fpe fpe silent /* #15 */ |
431 | BUILD_HANDLER ftlb ftlb none silent /* #16 */ | 434 | BUILD_HANDLER ftlb ftlb none silent /* #16 */ |
432 | BUILD_HANDLER msa msa sti silent /* #21 */ | 435 | BUILD_HANDLER msa msa sti silent /* #21 */ |
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 510452812594..7da6e324dd35 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c | |||
@@ -46,6 +46,26 @@ | |||
46 | #define CREATE_TRACE_POINTS | 46 | #define CREATE_TRACE_POINTS |
47 | #include <trace/events/syscalls.h> | 47 | #include <trace/events/syscalls.h> |
48 | 48 | ||
49 | static void init_fp_ctx(struct task_struct *target) | ||
50 | { | ||
51 | /* If FP has been used then the target already has context */ | ||
52 | if (tsk_used_math(target)) | ||
53 | return; | ||
54 | |||
55 | /* Begin with data registers set to all 1s... */ | ||
56 | memset(&target->thread.fpu.fpr, ~0, sizeof(target->thread.fpu.fpr)); | ||
57 | |||
58 | /* ...and FCSR zeroed */ | ||
59 | target->thread.fpu.fcr31 = 0; | ||
60 | |||
61 | /* | ||
62 | * Record that the target has "used" math, such that the context | ||
63 | * just initialised, and any modifications made by the caller, | ||
64 | * aren't discarded. | ||
65 | */ | ||
66 | set_stopped_child_used_math(target); | ||
67 | } | ||
68 | |||
49 | /* | 69 | /* |
50 | * Called by kernel/ptrace.c when detaching.. | 70 | * Called by kernel/ptrace.c when detaching.. |
51 | * | 71 | * |
@@ -142,6 +162,7 @@ int ptrace_setfpregs(struct task_struct *child, __u32 __user *data) | |||
142 | if (!access_ok(VERIFY_READ, data, 33 * 8)) | 162 | if (!access_ok(VERIFY_READ, data, 33 * 8)) |
143 | return -EIO; | 163 | return -EIO; |
144 | 164 | ||
165 | init_fp_ctx(child); | ||
145 | fregs = get_fpu_regs(child); | 166 | fregs = get_fpu_regs(child); |
146 | 167 | ||
147 | for (i = 0; i < 32; i++) { | 168 | for (i = 0; i < 32; i++) { |
@@ -439,6 +460,8 @@ static int fpr_set(struct task_struct *target, | |||
439 | 460 | ||
440 | /* XXX fcr31 */ | 461 | /* XXX fcr31 */ |
441 | 462 | ||
463 | init_fp_ctx(target); | ||
464 | |||
442 | if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) | 465 | if (sizeof(target->thread.fpu.fpr[i]) == sizeof(elf_fpreg_t)) |
443 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 466 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
444 | &target->thread.fpu, | 467 | &target->thread.fpu, |
@@ -660,12 +683,7 @@ long arch_ptrace(struct task_struct *child, long request, | |||
660 | case FPR_BASE ... FPR_BASE + 31: { | 683 | case FPR_BASE ... FPR_BASE + 31: { |
661 | union fpureg *fregs = get_fpu_regs(child); | 684 | union fpureg *fregs = get_fpu_regs(child); |
662 | 685 | ||
663 | if (!tsk_used_math(child)) { | 686 | init_fp_ctx(child); |
664 | /* FP not yet used */ | ||
665 | memset(&child->thread.fpu, ~0, | ||
666 | sizeof(child->thread.fpu)); | ||
667 | child->thread.fpu.fcr31 = 0; | ||
668 | } | ||
669 | #ifdef CONFIG_32BIT | 687 | #ifdef CONFIG_32BIT |
670 | if (test_thread_flag(TIF_32BIT_FPREGS)) { | 688 | if (test_thread_flag(TIF_32BIT_FPREGS)) { |
671 | /* | 689 | /* |
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 676c5030a953..1d88af26ba82 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S | |||
@@ -34,7 +34,6 @@ | |||
34 | .endm | 34 | .endm |
35 | 35 | ||
36 | .set noreorder | 36 | .set noreorder |
37 | .set MIPS_ISA_ARCH_LEVEL_RAW | ||
38 | 37 | ||
39 | LEAF(_save_fp_context) | 38 | LEAF(_save_fp_context) |
40 | .set push | 39 | .set push |
@@ -103,6 +102,7 @@ LEAF(_save_fp_context) | |||
103 | /* Save 32-bit process floating point context */ | 102 | /* Save 32-bit process floating point context */ |
104 | LEAF(_save_fp_context32) | 103 | LEAF(_save_fp_context32) |
105 | .set push | 104 | .set push |
105 | .set MIPS_ISA_ARCH_LEVEL_RAW | ||
106 | SET_HARDFLOAT | 106 | SET_HARDFLOAT |
107 | cfc1 t1, fcr31 | 107 | cfc1 t1, fcr31 |
108 | 108 | ||
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 33984c04b60b..5b4d711f878d 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -701,6 +701,13 @@ asmlinkage void do_ov(struct pt_regs *regs) | |||
701 | 701 | ||
702 | int process_fpemu_return(int sig, void __user *fault_addr) | 702 | int process_fpemu_return(int sig, void __user *fault_addr) |
703 | { | 703 | { |
704 | /* | ||
705 | * We can't allow the emulated instruction to leave any of the cause | ||
706 | * bits set in FCSR. If they were then the kernel would take an FP | ||
707 | * exception when restoring FP context. | ||
708 | */ | ||
709 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; | ||
710 | |||
704 | if (sig == SIGSEGV || sig == SIGBUS) { | 711 | if (sig == SIGSEGV || sig == SIGBUS) { |
705 | struct siginfo si = {0}; | 712 | struct siginfo si = {0}; |
706 | si.si_addr = fault_addr; | 713 | si.si_addr = fault_addr; |
@@ -781,6 +788,11 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
781 | if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), | 788 | if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), |
782 | SIGFPE) == NOTIFY_STOP) | 789 | SIGFPE) == NOTIFY_STOP) |
783 | goto out; | 790 | goto out; |
791 | |||
792 | /* Clear FCSR.Cause before enabling interrupts */ | ||
793 | write_32bit_cp1_register(CP1_STATUS, fcr31 & ~FPU_CSR_ALL_X); | ||
794 | local_irq_enable(); | ||
795 | |||
784 | die_if_kernel("FP exception in kernel code", regs); | 796 | die_if_kernel("FP exception in kernel code", regs); |
785 | 797 | ||
786 | if (fcr31 & FPU_CSR_UNI_X) { | 798 | if (fcr31 & FPU_CSR_UNI_X) { |
@@ -804,18 +816,12 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
804 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, | 816 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, |
805 | &fault_addr); | 817 | &fault_addr); |
806 | 818 | ||
807 | /* | 819 | /* If something went wrong, signal */ |
808 | * We can't allow the emulated instruction to leave any of | 820 | process_fpemu_return(sig, fault_addr); |
809 | * the cause bit set in $fcr31. | ||
810 | */ | ||
811 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; | ||
812 | 821 | ||
813 | /* Restore the hardware register state */ | 822 | /* Restore the hardware register state */ |
814 | own_fpu(1); /* Using the FPU again. */ | 823 | own_fpu(1); /* Using the FPU again. */ |
815 | 824 | ||
816 | /* If something went wrong, signal */ | ||
817 | process_fpemu_return(sig, fault_addr); | ||
818 | |||
819 | goto out; | 825 | goto out; |
820 | } else if (fcr31 & FPU_CSR_INV_X) | 826 | } else if (fcr31 & FPU_CSR_INV_X) |
821 | info.si_code = FPE_FLTINV; | 827 | info.si_code = FPE_FLTINV; |
@@ -1392,13 +1398,22 @@ out: | |||
1392 | exception_exit(prev_state); | 1398 | exception_exit(prev_state); |
1393 | } | 1399 | } |
1394 | 1400 | ||
1395 | asmlinkage void do_msa_fpe(struct pt_regs *regs) | 1401 | asmlinkage void do_msa_fpe(struct pt_regs *regs, unsigned int msacsr) |
1396 | { | 1402 | { |
1397 | enum ctx_state prev_state; | 1403 | enum ctx_state prev_state; |
1398 | 1404 | ||
1399 | prev_state = exception_enter(); | 1405 | prev_state = exception_enter(); |
1406 | if (notify_die(DIE_MSAFP, "MSA FP exception", regs, 0, | ||
1407 | regs_to_trapnr(regs), SIGFPE) == NOTIFY_STOP) | ||
1408 | goto out; | ||
1409 | |||
1410 | /* Clear MSACSR.Cause before enabling interrupts */ | ||
1411 | write_msa_csr(msacsr & ~MSA_CSR_CAUSEF); | ||
1412 | local_irq_enable(); | ||
1413 | |||
1400 | die_if_kernel("do_msa_fpe invoked from kernel context!", regs); | 1414 | die_if_kernel("do_msa_fpe invoked from kernel context!", regs); |
1401 | force_sig(SIGFPE, current); | 1415 | force_sig(SIGFPE, current); |
1416 | out: | ||
1402 | exception_exit(prev_state); | 1417 | exception_exit(prev_state); |
1403 | } | 1418 | } |
1404 | 1419 | ||
diff --git a/arch/mips/kvm/Makefile b/arch/mips/kvm/Makefile index 401fe027c261..637ebbebd549 100644 --- a/arch/mips/kvm/Makefile +++ b/arch/mips/kvm/Makefile | |||
@@ -1,13 +1,15 @@ | |||
1 | # Makefile for KVM support for MIPS | 1 | # Makefile for KVM support for MIPS |
2 | # | 2 | # |
3 | 3 | ||
4 | common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) | 4 | common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o) |
5 | 5 | ||
6 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/mips/kvm | 6 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/mips/kvm |
7 | 7 | ||
8 | kvm-objs := $(common-objs) mips.o emulate.o locore.o \ | 8 | common-objs-$(CONFIG_CPU_HAS_MSA) += msa.o |
9 | |||
10 | kvm-objs := $(common-objs-y) mips.o emulate.o locore.o \ | ||
9 | interrupt.o stats.o commpage.o \ | 11 | interrupt.o stats.o commpage.o \ |
10 | dyntrans.o trap_emul.o | 12 | dyntrans.o trap_emul.o fpu.o |
11 | 13 | ||
12 | obj-$(CONFIG_KVM) += kvm.o | 14 | obj-$(CONFIG_KVM) += kvm.o |
13 | obj-y += callback.o tlb.o | 15 | obj-y += callback.o tlb.o |
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index fb3e8dfd1ff6..6230f376a44e 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c | |||
@@ -884,6 +884,84 @@ enum emulation_result kvm_mips_emul_tlbp(struct kvm_vcpu *vcpu) | |||
884 | return EMULATE_DONE; | 884 | return EMULATE_DONE; |
885 | } | 885 | } |
886 | 886 | ||
887 | /** | ||
888 | * kvm_mips_config1_wrmask() - Find mask of writable bits in guest Config1 | ||
889 | * @vcpu: Virtual CPU. | ||
890 | * | ||
891 | * Finds the mask of bits which are writable in the guest's Config1 CP0 | ||
892 | * register, by userland (currently read-only to the guest). | ||
893 | */ | ||
894 | unsigned int kvm_mips_config1_wrmask(struct kvm_vcpu *vcpu) | ||
895 | { | ||
896 | unsigned int mask = 0; | ||
897 | |||
898 | /* Permit FPU to be present if FPU is supported */ | ||
899 | if (kvm_mips_guest_can_have_fpu(&vcpu->arch)) | ||
900 | mask |= MIPS_CONF1_FP; | ||
901 | |||
902 | return mask; | ||
903 | } | ||
904 | |||
905 | /** | ||
906 | * kvm_mips_config3_wrmask() - Find mask of writable bits in guest Config3 | ||
907 | * @vcpu: Virtual CPU. | ||
908 | * | ||
909 | * Finds the mask of bits which are writable in the guest's Config3 CP0 | ||
910 | * register, by userland (currently read-only to the guest). | ||
911 | */ | ||
912 | unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu) | ||
913 | { | ||
914 | /* Config4 is optional */ | ||
915 | unsigned int mask = MIPS_CONF_M; | ||
916 | |||
917 | /* Permit MSA to be present if MSA is supported */ | ||
918 | if (kvm_mips_guest_can_have_msa(&vcpu->arch)) | ||
919 | mask |= MIPS_CONF3_MSA; | ||
920 | |||
921 | return mask; | ||
922 | } | ||
923 | |||
924 | /** | ||
925 | * kvm_mips_config4_wrmask() - Find mask of writable bits in guest Config4 | ||
926 | * @vcpu: Virtual CPU. | ||
927 | * | ||
928 | * Finds the mask of bits which are writable in the guest's Config4 CP0 | ||
929 | * register, by userland (currently read-only to the guest). | ||
930 | */ | ||
931 | unsigned int kvm_mips_config4_wrmask(struct kvm_vcpu *vcpu) | ||
932 | { | ||
933 | /* Config5 is optional */ | ||
934 | return MIPS_CONF_M; | ||
935 | } | ||
936 | |||
937 | /** | ||
938 | * kvm_mips_config5_wrmask() - Find mask of writable bits in guest Config5 | ||
939 | * @vcpu: Virtual CPU. | ||
940 | * | ||
941 | * Finds the mask of bits which are writable in the guest's Config5 CP0 | ||
942 | * register, by the guest itself. | ||
943 | */ | ||
944 | unsigned int kvm_mips_config5_wrmask(struct kvm_vcpu *vcpu) | ||
945 | { | ||
946 | unsigned int mask = 0; | ||
947 | |||
948 | /* Permit MSAEn changes if MSA supported and enabled */ | ||
949 | if (kvm_mips_guest_has_msa(&vcpu->arch)) | ||
950 | mask |= MIPS_CONF5_MSAEN; | ||
951 | |||
952 | /* | ||
953 | * Permit guest FPU mode changes if FPU is enabled and the relevant | ||
954 | * feature exists according to FIR register. | ||
955 | */ | ||
956 | if (kvm_mips_guest_has_fpu(&vcpu->arch)) { | ||
957 | if (cpu_has_fre) | ||
958 | mask |= MIPS_CONF5_FRE; | ||
959 | /* We don't support UFR or UFE */ | ||
960 | } | ||
961 | |||
962 | return mask; | ||
963 | } | ||
964 | |||
887 | enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, | 965 | enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, |
888 | uint32_t cause, struct kvm_run *run, | 966 | uint32_t cause, struct kvm_run *run, |
889 | struct kvm_vcpu *vcpu) | 967 | struct kvm_vcpu *vcpu) |
@@ -1021,18 +1099,114 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, | |||
1021 | kvm_mips_write_compare(vcpu, | 1099 | kvm_mips_write_compare(vcpu, |
1022 | vcpu->arch.gprs[rt]); | 1100 | vcpu->arch.gprs[rt]); |
1023 | } else if ((rd == MIPS_CP0_STATUS) && (sel == 0)) { | 1101 | } else if ((rd == MIPS_CP0_STATUS) && (sel == 0)) { |
1024 | kvm_write_c0_guest_status(cop0, | 1102 | unsigned int old_val, val, change; |
1025 | vcpu->arch.gprs[rt]); | 1103 | |
1104 | old_val = kvm_read_c0_guest_status(cop0); | ||
1105 | val = vcpu->arch.gprs[rt]; | ||
1106 | change = val ^ old_val; | ||
1107 | |||
1108 | /* Make sure that the NMI bit is never set */ | ||
1109 | val &= ~ST0_NMI; | ||
1110 | |||
1111 | /* | ||
1112 | * Don't allow CU1 or FR to be set unless FPU | ||
1113 | * capability enabled and exists in guest | ||
1114 | * configuration. | ||
1115 | */ | ||
1116 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
1117 | val &= ~(ST0_CU1 | ST0_FR); | ||
1118 | |||
1119 | /* | ||
1120 | * Also don't allow FR to be set if host doesn't | ||
1121 | * support it. | ||
1122 | */ | ||
1123 | if (!(current_cpu_data.fpu_id & MIPS_FPIR_F64)) | ||
1124 | val &= ~ST0_FR; | ||
1125 | |||
1126 | |||
1127 | /* Handle changes in FPU mode */ | ||
1128 | preempt_disable(); | ||
1129 | |||
1130 | /* | ||
1131 | * FPU and Vector register state is made | ||
1132 | * UNPREDICTABLE by a change of FR, so don't | ||
1133 | * even bother saving it. | ||
1134 | */ | ||
1135 | if (change & ST0_FR) | ||
1136 | kvm_drop_fpu(vcpu); | ||
1137 | |||
1138 | /* | ||
1139 | * If MSA state is already live, it is undefined | ||
1140 | * how it interacts with FR=0 FPU state, and we | ||
1141 | * don't want to hit reserved instruction | ||
1142 | * exceptions trying to save the MSA state later | ||
1143 | * when CU=1 && FR=1, so play it safe and save | ||
1144 | * it first. | ||
1145 | */ | ||
1146 | if (change & ST0_CU1 && !(val & ST0_FR) && | ||
1147 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) | ||
1148 | kvm_lose_fpu(vcpu); | ||
1149 | |||
1026 | /* | 1150 | /* |
1027 | * Make sure that CU1 and NMI bits are | 1151 | * Propagate CU1 (FPU enable) changes |
1028 | * never set | 1152 | * immediately if the FPU context is already |
1153 | * loaded. When disabling we leave the context | ||
1154 | * loaded so it can be quickly enabled again in | ||
1155 | * the near future. | ||
1029 | */ | 1156 | */ |
1030 | kvm_clear_c0_guest_status(cop0, | 1157 | if (change & ST0_CU1 && |
1031 | (ST0_CU1 | ST0_NMI)); | 1158 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) |
1159 | change_c0_status(ST0_CU1, val); | ||
1160 | |||
1161 | preempt_enable(); | ||
1162 | |||
1163 | kvm_write_c0_guest_status(cop0, val); | ||
1032 | 1164 | ||
1033 | #ifdef CONFIG_KVM_MIPS_DYN_TRANS | 1165 | #ifdef CONFIG_KVM_MIPS_DYN_TRANS |
1034 | kvm_mips_trans_mtc0(inst, opc, vcpu); | 1166 | /* |
1167 | * If FPU present, we need CU1/FR bits to take | ||
1168 | * effect fairly soon. | ||
1169 | */ | ||
1170 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
1171 | kvm_mips_trans_mtc0(inst, opc, vcpu); | ||
1035 | #endif | 1172 | #endif |
1173 | } else if ((rd == MIPS_CP0_CONFIG) && (sel == 5)) { | ||
1174 | unsigned int old_val, val, change, wrmask; | ||
1175 | |||
1176 | old_val = kvm_read_c0_guest_config5(cop0); | ||
1177 | val = vcpu->arch.gprs[rt]; | ||
1178 | |||
1179 | /* Only a few bits are writable in Config5 */ | ||
1180 | wrmask = kvm_mips_config5_wrmask(vcpu); | ||
1181 | change = (val ^ old_val) & wrmask; | ||
1182 | val = old_val ^ change; | ||
1183 | |||
1184 | |||
1185 | /* Handle changes in FPU/MSA modes */ | ||
1186 | preempt_disable(); | ||
1187 | |||
1188 | /* | ||
1189 | * Propagate FRE changes immediately if the FPU | ||
1190 | * context is already loaded. | ||
1191 | */ | ||
1192 | if (change & MIPS_CONF5_FRE && | ||
1193 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) | ||
1194 | change_c0_config5(MIPS_CONF5_FRE, val); | ||
1195 | |||
1196 | /* | ||
1197 | * Propagate MSAEn changes immediately if the | ||
1198 | * MSA context is already loaded. When disabling | ||
1199 | * we leave the context loaded so it can be | ||
1200 | * quickly enabled again in the near future. | ||
1201 | */ | ||
1202 | if (change & MIPS_CONF5_MSAEN && | ||
1203 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) | ||
1204 | change_c0_config5(MIPS_CONF5_MSAEN, | ||
1205 | val); | ||
1206 | |||
1207 | preempt_enable(); | ||
1208 | |||
1209 | kvm_write_c0_guest_config5(cop0, val); | ||
1036 | } else if ((rd == MIPS_CP0_CAUSE) && (sel == 0)) { | 1210 | } else if ((rd == MIPS_CP0_CAUSE) && (sel == 0)) { |
1037 | uint32_t old_cause, new_cause; | 1211 | uint32_t old_cause, new_cause; |
1038 | 1212 | ||
@@ -1970,6 +2144,146 @@ enum emulation_result kvm_mips_emulate_bp_exc(unsigned long cause, | |||
1970 | return er; | 2144 | return er; |
1971 | } | 2145 | } |
1972 | 2146 | ||
2147 | enum emulation_result kvm_mips_emulate_trap_exc(unsigned long cause, | ||
2148 | uint32_t *opc, | ||
2149 | struct kvm_run *run, | ||
2150 | struct kvm_vcpu *vcpu) | ||
2151 | { | ||
2152 | struct mips_coproc *cop0 = vcpu->arch.cop0; | ||
2153 | struct kvm_vcpu_arch *arch = &vcpu->arch; | ||
2154 | enum emulation_result er = EMULATE_DONE; | ||
2155 | |||
2156 | if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { | ||
2157 | /* save old pc */ | ||
2158 | kvm_write_c0_guest_epc(cop0, arch->pc); | ||
2159 | kvm_set_c0_guest_status(cop0, ST0_EXL); | ||
2160 | |||
2161 | if (cause & CAUSEF_BD) | ||
2162 | kvm_set_c0_guest_cause(cop0, CAUSEF_BD); | ||
2163 | else | ||
2164 | kvm_clear_c0_guest_cause(cop0, CAUSEF_BD); | ||
2165 | |||
2166 | kvm_debug("Delivering TRAP @ pc %#lx\n", arch->pc); | ||
2167 | |||
2168 | kvm_change_c0_guest_cause(cop0, (0xff), | ||
2169 | (T_TRAP << CAUSEB_EXCCODE)); | ||
2170 | |||
2171 | /* Set PC to the exception entry point */ | ||
2172 | arch->pc = KVM_GUEST_KSEG0 + 0x180; | ||
2173 | |||
2174 | } else { | ||
2175 | kvm_err("Trying to deliver TRAP when EXL is already set\n"); | ||
2176 | er = EMULATE_FAIL; | ||
2177 | } | ||
2178 | |||
2179 | return er; | ||
2180 | } | ||
2181 | |||
2182 | enum emulation_result kvm_mips_emulate_msafpe_exc(unsigned long cause, | ||
2183 | uint32_t *opc, | ||
2184 | struct kvm_run *run, | ||
2185 | struct kvm_vcpu *vcpu) | ||
2186 | { | ||
2187 | struct mips_coproc *cop0 = vcpu->arch.cop0; | ||
2188 | struct kvm_vcpu_arch *arch = &vcpu->arch; | ||
2189 | enum emulation_result er = EMULATE_DONE; | ||
2190 | |||
2191 | if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { | ||
2192 | /* save old pc */ | ||
2193 | kvm_write_c0_guest_epc(cop0, arch->pc); | ||
2194 | kvm_set_c0_guest_status(cop0, ST0_EXL); | ||
2195 | |||
2196 | if (cause & CAUSEF_BD) | ||
2197 | kvm_set_c0_guest_cause(cop0, CAUSEF_BD); | ||
2198 | else | ||
2199 | kvm_clear_c0_guest_cause(cop0, CAUSEF_BD); | ||
2200 | |||
2201 | kvm_debug("Delivering MSAFPE @ pc %#lx\n", arch->pc); | ||
2202 | |||
2203 | kvm_change_c0_guest_cause(cop0, (0xff), | ||
2204 | (T_MSAFPE << CAUSEB_EXCCODE)); | ||
2205 | |||
2206 | /* Set PC to the exception entry point */ | ||
2207 | arch->pc = KVM_GUEST_KSEG0 + 0x180; | ||
2208 | |||
2209 | } else { | ||
2210 | kvm_err("Trying to deliver MSAFPE when EXL is already set\n"); | ||
2211 | er = EMULATE_FAIL; | ||
2212 | } | ||
2213 | |||
2214 | return er; | ||
2215 | } | ||
2216 | |||
2217 | enum emulation_result kvm_mips_emulate_fpe_exc(unsigned long cause, | ||
2218 | uint32_t *opc, | ||
2219 | struct kvm_run *run, | ||
2220 | struct kvm_vcpu *vcpu) | ||
2221 | { | ||
2222 | struct mips_coproc *cop0 = vcpu->arch.cop0; | ||
2223 | struct kvm_vcpu_arch *arch = &vcpu->arch; | ||
2224 | enum emulation_result er = EMULATE_DONE; | ||
2225 | |||
2226 | if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { | ||
2227 | /* save old pc */ | ||
2228 | kvm_write_c0_guest_epc(cop0, arch->pc); | ||
2229 | kvm_set_c0_guest_status(cop0, ST0_EXL); | ||
2230 | |||
2231 | if (cause & CAUSEF_BD) | ||
2232 | kvm_set_c0_guest_cause(cop0, CAUSEF_BD); | ||
2233 | else | ||
2234 | kvm_clear_c0_guest_cause(cop0, CAUSEF_BD); | ||
2235 | |||
2236 | kvm_debug("Delivering FPE @ pc %#lx\n", arch->pc); | ||
2237 | |||
2238 | kvm_change_c0_guest_cause(cop0, (0xff), | ||
2239 | (T_FPE << CAUSEB_EXCCODE)); | ||
2240 | |||
2241 | /* Set PC to the exception entry point */ | ||
2242 | arch->pc = KVM_GUEST_KSEG0 + 0x180; | ||
2243 | |||
2244 | } else { | ||
2245 | kvm_err("Trying to deliver FPE when EXL is already set\n"); | ||
2246 | er = EMULATE_FAIL; | ||
2247 | } | ||
2248 | |||
2249 | return er; | ||
2250 | } | ||
2251 | |||
2252 | enum emulation_result kvm_mips_emulate_msadis_exc(unsigned long cause, | ||
2253 | uint32_t *opc, | ||
2254 | struct kvm_run *run, | ||
2255 | struct kvm_vcpu *vcpu) | ||
2256 | { | ||
2257 | struct mips_coproc *cop0 = vcpu->arch.cop0; | ||
2258 | struct kvm_vcpu_arch *arch = &vcpu->arch; | ||
2259 | enum emulation_result er = EMULATE_DONE; | ||
2260 | |||
2261 | if ((kvm_read_c0_guest_status(cop0) & ST0_EXL) == 0) { | ||
2262 | /* save old pc */ | ||
2263 | kvm_write_c0_guest_epc(cop0, arch->pc); | ||
2264 | kvm_set_c0_guest_status(cop0, ST0_EXL); | ||
2265 | |||
2266 | if (cause & CAUSEF_BD) | ||
2267 | kvm_set_c0_guest_cause(cop0, CAUSEF_BD); | ||
2268 | else | ||
2269 | kvm_clear_c0_guest_cause(cop0, CAUSEF_BD); | ||
2270 | |||
2271 | kvm_debug("Delivering MSADIS @ pc %#lx\n", arch->pc); | ||
2272 | |||
2273 | kvm_change_c0_guest_cause(cop0, (0xff), | ||
2274 | (T_MSADIS << CAUSEB_EXCCODE)); | ||
2275 | |||
2276 | /* Set PC to the exception entry point */ | ||
2277 | arch->pc = KVM_GUEST_KSEG0 + 0x180; | ||
2278 | |||
2279 | } else { | ||
2280 | kvm_err("Trying to deliver MSADIS when EXL is already set\n"); | ||
2281 | er = EMULATE_FAIL; | ||
2282 | } | ||
2283 | |||
2284 | return er; | ||
2285 | } | ||
2286 | |||
1973 | /* ll/sc, rdhwr, sync emulation */ | 2287 | /* ll/sc, rdhwr, sync emulation */ |
1974 | 2288 | ||
1975 | #define OPCODE 0xfc000000 | 2289 | #define OPCODE 0xfc000000 |
@@ -2176,6 +2490,10 @@ enum emulation_result kvm_mips_check_privilege(unsigned long cause, | |||
2176 | case T_SYSCALL: | 2490 | case T_SYSCALL: |
2177 | case T_BREAK: | 2491 | case T_BREAK: |
2178 | case T_RES_INST: | 2492 | case T_RES_INST: |
2493 | case T_TRAP: | ||
2494 | case T_MSAFPE: | ||
2495 | case T_FPE: | ||
2496 | case T_MSADIS: | ||
2179 | break; | 2497 | break; |
2180 | 2498 | ||
2181 | case T_COP_UNUSABLE: | 2499 | case T_COP_UNUSABLE: |
diff --git a/arch/mips/kvm/fpu.S b/arch/mips/kvm/fpu.S new file mode 100644 index 000000000000..531fbf5131c0 --- /dev/null +++ b/arch/mips/kvm/fpu.S | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * FPU context handling code for KVM. | ||
7 | * | ||
8 | * Copyright (C) 2015 Imagination Technologies Ltd. | ||
9 | */ | ||
10 | |||
11 | #include <asm/asm.h> | ||
12 | #include <asm/asm-offsets.h> | ||
13 | #include <asm/fpregdef.h> | ||
14 | #include <asm/mipsregs.h> | ||
15 | #include <asm/regdef.h> | ||
16 | |||
17 | .set noreorder | ||
18 | .set noat | ||
19 | |||
20 | LEAF(__kvm_save_fpu) | ||
21 | .set push | ||
22 | .set mips64r2 | ||
23 | SET_HARDFLOAT | ||
24 | mfc0 t0, CP0_STATUS | ||
25 | sll t0, t0, 5 # is Status.FR set? | ||
26 | bgez t0, 1f # no: skip odd doubles | ||
27 | nop | ||
28 | sdc1 $f1, VCPU_FPR1(a0) | ||
29 | sdc1 $f3, VCPU_FPR3(a0) | ||
30 | sdc1 $f5, VCPU_FPR5(a0) | ||
31 | sdc1 $f7, VCPU_FPR7(a0) | ||
32 | sdc1 $f9, VCPU_FPR9(a0) | ||
33 | sdc1 $f11, VCPU_FPR11(a0) | ||
34 | sdc1 $f13, VCPU_FPR13(a0) | ||
35 | sdc1 $f15, VCPU_FPR15(a0) | ||
36 | sdc1 $f17, VCPU_FPR17(a0) | ||
37 | sdc1 $f19, VCPU_FPR19(a0) | ||
38 | sdc1 $f21, VCPU_FPR21(a0) | ||
39 | sdc1 $f23, VCPU_FPR23(a0) | ||
40 | sdc1 $f25, VCPU_FPR25(a0) | ||
41 | sdc1 $f27, VCPU_FPR27(a0) | ||
42 | sdc1 $f29, VCPU_FPR29(a0) | ||
43 | sdc1 $f31, VCPU_FPR31(a0) | ||
44 | 1: sdc1 $f0, VCPU_FPR0(a0) | ||
45 | sdc1 $f2, VCPU_FPR2(a0) | ||
46 | sdc1 $f4, VCPU_FPR4(a0) | ||
47 | sdc1 $f6, VCPU_FPR6(a0) | ||
48 | sdc1 $f8, VCPU_FPR8(a0) | ||
49 | sdc1 $f10, VCPU_FPR10(a0) | ||
50 | sdc1 $f12, VCPU_FPR12(a0) | ||
51 | sdc1 $f14, VCPU_FPR14(a0) | ||
52 | sdc1 $f16, VCPU_FPR16(a0) | ||
53 | sdc1 $f18, VCPU_FPR18(a0) | ||
54 | sdc1 $f20, VCPU_FPR20(a0) | ||
55 | sdc1 $f22, VCPU_FPR22(a0) | ||
56 | sdc1 $f24, VCPU_FPR24(a0) | ||
57 | sdc1 $f26, VCPU_FPR26(a0) | ||
58 | sdc1 $f28, VCPU_FPR28(a0) | ||
59 | jr ra | ||
60 | sdc1 $f30, VCPU_FPR30(a0) | ||
61 | .set pop | ||
62 | END(__kvm_save_fpu) | ||
63 | |||
64 | LEAF(__kvm_restore_fpu) | ||
65 | .set push | ||
66 | .set mips64r2 | ||
67 | SET_HARDFLOAT | ||
68 | mfc0 t0, CP0_STATUS | ||
69 | sll t0, t0, 5 # is Status.FR set? | ||
70 | bgez t0, 1f # no: skip odd doubles | ||
71 | nop | ||
72 | ldc1 $f1, VCPU_FPR1(a0) | ||
73 | ldc1 $f3, VCPU_FPR3(a0) | ||
74 | ldc1 $f5, VCPU_FPR5(a0) | ||
75 | ldc1 $f7, VCPU_FPR7(a0) | ||
76 | ldc1 $f9, VCPU_FPR9(a0) | ||
77 | ldc1 $f11, VCPU_FPR11(a0) | ||
78 | ldc1 $f13, VCPU_FPR13(a0) | ||
79 | ldc1 $f15, VCPU_FPR15(a0) | ||
80 | ldc1 $f17, VCPU_FPR17(a0) | ||
81 | ldc1 $f19, VCPU_FPR19(a0) | ||
82 | ldc1 $f21, VCPU_FPR21(a0) | ||
83 | ldc1 $f23, VCPU_FPR23(a0) | ||
84 | ldc1 $f25, VCPU_FPR25(a0) | ||
85 | ldc1 $f27, VCPU_FPR27(a0) | ||
86 | ldc1 $f29, VCPU_FPR29(a0) | ||
87 | ldc1 $f31, VCPU_FPR31(a0) | ||
88 | 1: ldc1 $f0, VCPU_FPR0(a0) | ||
89 | ldc1 $f2, VCPU_FPR2(a0) | ||
90 | ldc1 $f4, VCPU_FPR4(a0) | ||
91 | ldc1 $f6, VCPU_FPR6(a0) | ||
92 | ldc1 $f8, VCPU_FPR8(a0) | ||
93 | ldc1 $f10, VCPU_FPR10(a0) | ||
94 | ldc1 $f12, VCPU_FPR12(a0) | ||
95 | ldc1 $f14, VCPU_FPR14(a0) | ||
96 | ldc1 $f16, VCPU_FPR16(a0) | ||
97 | ldc1 $f18, VCPU_FPR18(a0) | ||
98 | ldc1 $f20, VCPU_FPR20(a0) | ||
99 | ldc1 $f22, VCPU_FPR22(a0) | ||
100 | ldc1 $f24, VCPU_FPR24(a0) | ||
101 | ldc1 $f26, VCPU_FPR26(a0) | ||
102 | ldc1 $f28, VCPU_FPR28(a0) | ||
103 | jr ra | ||
104 | ldc1 $f30, VCPU_FPR30(a0) | ||
105 | .set pop | ||
106 | END(__kvm_restore_fpu) | ||
107 | |||
108 | LEAF(__kvm_restore_fcsr) | ||
109 | .set push | ||
110 | SET_HARDFLOAT | ||
111 | lw t0, VCPU_FCR31(a0) | ||
112 | /* | ||
113 | * The ctc1 must stay at this offset in __kvm_restore_fcsr. | ||
114 | * See kvm_mips_csr_die_notify() which handles t0 containing a value | ||
115 | * which triggers an FP Exception, which must be stepped over and | ||
116 | * ignored since the set cause bits must remain there for the guest. | ||
117 | */ | ||
118 | ctc1 t0, fcr31 | ||
119 | jr ra | ||
120 | nop | ||
121 | .set pop | ||
122 | END(__kvm_restore_fcsr) | ||
diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S index 4a68b176d6e4..c567240386a0 100644 --- a/arch/mips/kvm/locore.S +++ b/arch/mips/kvm/locore.S | |||
@@ -36,6 +36,8 @@ | |||
36 | #define PT_HOST_USERLOCAL PT_EPC | 36 | #define PT_HOST_USERLOCAL PT_EPC |
37 | 37 | ||
38 | #define CP0_DDATA_LO $28,3 | 38 | #define CP0_DDATA_LO $28,3 |
39 | #define CP0_CONFIG3 $16,3 | ||
40 | #define CP0_CONFIG5 $16,5 | ||
39 | #define CP0_EBASE $15,1 | 41 | #define CP0_EBASE $15,1 |
40 | 42 | ||
41 | #define CP0_INTCTL $12,1 | 43 | #define CP0_INTCTL $12,1 |
@@ -353,6 +355,42 @@ NESTED (MIPSX(GuestException), CALLFRAME_SIZ, ra) | |||
353 | LONG_L k0, VCPU_HOST_EBASE(k1) | 355 | LONG_L k0, VCPU_HOST_EBASE(k1) |
354 | mtc0 k0,CP0_EBASE | 356 | mtc0 k0,CP0_EBASE |
355 | 357 | ||
358 | /* | ||
359 | * If FPU is enabled, save FCR31 and clear it so that later ctc1's don't | ||
360 | * trigger FPE for pending exceptions. | ||
361 | */ | ||
362 | .set at | ||
363 | and v1, v0, ST0_CU1 | ||
364 | beqz v1, 1f | ||
365 | nop | ||
366 | .set push | ||
367 | SET_HARDFLOAT | ||
368 | cfc1 t0, fcr31 | ||
369 | sw t0, VCPU_FCR31(k1) | ||
370 | ctc1 zero,fcr31 | ||
371 | .set pop | ||
372 | .set noat | ||
373 | 1: | ||
374 | |||
375 | #ifdef CONFIG_CPU_HAS_MSA | ||
376 | /* | ||
377 | * If MSA is enabled, save MSACSR and clear it so that later | ||
378 | * instructions don't trigger MSAFPE for pending exceptions. | ||
379 | */ | ||
380 | mfc0 t0, CP0_CONFIG3 | ||
381 | ext t0, t0, 28, 1 /* MIPS_CONF3_MSAP */ | ||
382 | beqz t0, 1f | ||
383 | nop | ||
384 | mfc0 t0, CP0_CONFIG5 | ||
385 | ext t0, t0, 27, 1 /* MIPS_CONF5_MSAEN */ | ||
386 | beqz t0, 1f | ||
387 | nop | ||
388 | _cfcmsa t0, MSA_CSR | ||
389 | sw t0, VCPU_MSA_CSR(k1) | ||
390 | _ctcmsa MSA_CSR, zero | ||
391 | 1: | ||
392 | #endif | ||
393 | |||
356 | /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */ | 394 | /* Now that the new EBASE has been loaded, unset BEV and KSU_USER */ |
357 | .set at | 395 | .set at |
358 | and v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE) | 396 | and v0, v0, ~(ST0_EXL | KSU_USER | ST0_IE) |
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index c9eccf5df912..bb68e8d520e8 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/err.h> | 13 | #include <linux/err.h> |
14 | #include <linux/kdebug.h> | ||
14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
15 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
16 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
@@ -48,6 +49,10 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
48 | { "syscall", VCPU_STAT(syscall_exits), KVM_STAT_VCPU }, | 49 | { "syscall", VCPU_STAT(syscall_exits), KVM_STAT_VCPU }, |
49 | { "resvd_inst", VCPU_STAT(resvd_inst_exits), KVM_STAT_VCPU }, | 50 | { "resvd_inst", VCPU_STAT(resvd_inst_exits), KVM_STAT_VCPU }, |
50 | { "break_inst", VCPU_STAT(break_inst_exits), KVM_STAT_VCPU }, | 51 | { "break_inst", VCPU_STAT(break_inst_exits), KVM_STAT_VCPU }, |
52 | { "trap_inst", VCPU_STAT(trap_inst_exits), KVM_STAT_VCPU }, | ||
53 | { "msa_fpe", VCPU_STAT(msa_fpe_exits), KVM_STAT_VCPU }, | ||
54 | { "fpe", VCPU_STAT(fpe_exits), KVM_STAT_VCPU }, | ||
55 | { "msa_disabled", VCPU_STAT(msa_disabled_exits), KVM_STAT_VCPU }, | ||
51 | { "flush_dcache", VCPU_STAT(flush_dcache_exits), KVM_STAT_VCPU }, | 56 | { "flush_dcache", VCPU_STAT(flush_dcache_exits), KVM_STAT_VCPU }, |
52 | { "halt_successful_poll", VCPU_STAT(halt_successful_poll), KVM_STAT_VCPU }, | 57 | { "halt_successful_poll", VCPU_STAT(halt_successful_poll), KVM_STAT_VCPU }, |
53 | { "halt_wakeup", VCPU_STAT(halt_wakeup), KVM_STAT_VCPU }, | 58 | { "halt_wakeup", VCPU_STAT(halt_wakeup), KVM_STAT_VCPU }, |
@@ -504,10 +509,13 @@ static u64 kvm_mips_get_one_regs[] = { | |||
504 | KVM_REG_MIPS_CP0_STATUS, | 509 | KVM_REG_MIPS_CP0_STATUS, |
505 | KVM_REG_MIPS_CP0_CAUSE, | 510 | KVM_REG_MIPS_CP0_CAUSE, |
506 | KVM_REG_MIPS_CP0_EPC, | 511 | KVM_REG_MIPS_CP0_EPC, |
512 | KVM_REG_MIPS_CP0_PRID, | ||
507 | KVM_REG_MIPS_CP0_CONFIG, | 513 | KVM_REG_MIPS_CP0_CONFIG, |
508 | KVM_REG_MIPS_CP0_CONFIG1, | 514 | KVM_REG_MIPS_CP0_CONFIG1, |
509 | KVM_REG_MIPS_CP0_CONFIG2, | 515 | KVM_REG_MIPS_CP0_CONFIG2, |
510 | KVM_REG_MIPS_CP0_CONFIG3, | 516 | KVM_REG_MIPS_CP0_CONFIG3, |
517 | KVM_REG_MIPS_CP0_CONFIG4, | ||
518 | KVM_REG_MIPS_CP0_CONFIG5, | ||
511 | KVM_REG_MIPS_CP0_CONFIG7, | 519 | KVM_REG_MIPS_CP0_CONFIG7, |
512 | KVM_REG_MIPS_CP0_ERROREPC, | 520 | KVM_REG_MIPS_CP0_ERROREPC, |
513 | 521 | ||
@@ -520,10 +528,14 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, | |||
520 | const struct kvm_one_reg *reg) | 528 | const struct kvm_one_reg *reg) |
521 | { | 529 | { |
522 | struct mips_coproc *cop0 = vcpu->arch.cop0; | 530 | struct mips_coproc *cop0 = vcpu->arch.cop0; |
531 | struct mips_fpu_struct *fpu = &vcpu->arch.fpu; | ||
523 | int ret; | 532 | int ret; |
524 | s64 v; | 533 | s64 v; |
534 | s64 vs[2]; | ||
535 | unsigned int idx; | ||
525 | 536 | ||
526 | switch (reg->id) { | 537 | switch (reg->id) { |
538 | /* General purpose registers */ | ||
527 | case KVM_REG_MIPS_R0 ... KVM_REG_MIPS_R31: | 539 | case KVM_REG_MIPS_R0 ... KVM_REG_MIPS_R31: |
528 | v = (long)vcpu->arch.gprs[reg->id - KVM_REG_MIPS_R0]; | 540 | v = (long)vcpu->arch.gprs[reg->id - KVM_REG_MIPS_R0]; |
529 | break; | 541 | break; |
@@ -537,6 +549,67 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, | |||
537 | v = (long)vcpu->arch.pc; | 549 | v = (long)vcpu->arch.pc; |
538 | break; | 550 | break; |
539 | 551 | ||
552 | /* Floating point registers */ | ||
553 | case KVM_REG_MIPS_FPR_32(0) ... KVM_REG_MIPS_FPR_32(31): | ||
554 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
555 | return -EINVAL; | ||
556 | idx = reg->id - KVM_REG_MIPS_FPR_32(0); | ||
557 | /* Odd singles in top of even double when FR=0 */ | ||
558 | if (kvm_read_c0_guest_status(cop0) & ST0_FR) | ||
559 | v = get_fpr32(&fpu->fpr[idx], 0); | ||
560 | else | ||
561 | v = get_fpr32(&fpu->fpr[idx & ~1], idx & 1); | ||
562 | break; | ||
563 | case KVM_REG_MIPS_FPR_64(0) ... KVM_REG_MIPS_FPR_64(31): | ||
564 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
565 | return -EINVAL; | ||
566 | idx = reg->id - KVM_REG_MIPS_FPR_64(0); | ||
567 | /* Can't access odd doubles in FR=0 mode */ | ||
568 | if (idx & 1 && !(kvm_read_c0_guest_status(cop0) & ST0_FR)) | ||
569 | return -EINVAL; | ||
570 | v = get_fpr64(&fpu->fpr[idx], 0); | ||
571 | break; | ||
572 | case KVM_REG_MIPS_FCR_IR: | ||
573 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
574 | return -EINVAL; | ||
575 | v = boot_cpu_data.fpu_id; | ||
576 | break; | ||
577 | case KVM_REG_MIPS_FCR_CSR: | ||
578 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
579 | return -EINVAL; | ||
580 | v = fpu->fcr31; | ||
581 | break; | ||
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 | |||
612 | /* Co-processor 0 registers */ | ||
540 | case KVM_REG_MIPS_CP0_INDEX: | 613 | case KVM_REG_MIPS_CP0_INDEX: |
541 | v = (long)kvm_read_c0_guest_index(cop0); | 614 | v = (long)kvm_read_c0_guest_index(cop0); |
542 | break; | 615 | break; |
@@ -573,8 +646,8 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, | |||
573 | case KVM_REG_MIPS_CP0_EPC: | 646 | case KVM_REG_MIPS_CP0_EPC: |
574 | v = (long)kvm_read_c0_guest_epc(cop0); | 647 | v = (long)kvm_read_c0_guest_epc(cop0); |
575 | break; | 648 | break; |
576 | case KVM_REG_MIPS_CP0_ERROREPC: | 649 | case KVM_REG_MIPS_CP0_PRID: |
577 | v = (long)kvm_read_c0_guest_errorepc(cop0); | 650 | v = (long)kvm_read_c0_guest_prid(cop0); |
578 | break; | 651 | break; |
579 | case KVM_REG_MIPS_CP0_CONFIG: | 652 | case KVM_REG_MIPS_CP0_CONFIG: |
580 | v = (long)kvm_read_c0_guest_config(cop0); | 653 | v = (long)kvm_read_c0_guest_config(cop0); |
@@ -588,9 +661,18 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, | |||
588 | case KVM_REG_MIPS_CP0_CONFIG3: | 661 | case KVM_REG_MIPS_CP0_CONFIG3: |
589 | v = (long)kvm_read_c0_guest_config3(cop0); | 662 | v = (long)kvm_read_c0_guest_config3(cop0); |
590 | break; | 663 | break; |
664 | case KVM_REG_MIPS_CP0_CONFIG4: | ||
665 | v = (long)kvm_read_c0_guest_config4(cop0); | ||
666 | break; | ||
667 | case KVM_REG_MIPS_CP0_CONFIG5: | ||
668 | v = (long)kvm_read_c0_guest_config5(cop0); | ||
669 | break; | ||
591 | case KVM_REG_MIPS_CP0_CONFIG7: | 670 | case KVM_REG_MIPS_CP0_CONFIG7: |
592 | v = (long)kvm_read_c0_guest_config7(cop0); | 671 | v = (long)kvm_read_c0_guest_config7(cop0); |
593 | break; | 672 | break; |
673 | case KVM_REG_MIPS_CP0_ERROREPC: | ||
674 | v = (long)kvm_read_c0_guest_errorepc(cop0); | ||
675 | break; | ||
594 | /* registers to be handled specially */ | 676 | /* registers to be handled specially */ |
595 | case KVM_REG_MIPS_CP0_COUNT: | 677 | case KVM_REG_MIPS_CP0_COUNT: |
596 | case KVM_REG_MIPS_COUNT_CTL: | 678 | case KVM_REG_MIPS_COUNT_CTL: |
@@ -612,6 +694,10 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, | |||
612 | u32 v32 = (u32)v; | 694 | u32 v32 = (u32)v; |
613 | 695 | ||
614 | 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); | ||
615 | } else { | 701 | } else { |
616 | return -EINVAL; | 702 | return -EINVAL; |
617 | } | 703 | } |
@@ -621,7 +707,10 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, | |||
621 | const struct kvm_one_reg *reg) | 707 | const struct kvm_one_reg *reg) |
622 | { | 708 | { |
623 | struct mips_coproc *cop0 = vcpu->arch.cop0; | 709 | struct mips_coproc *cop0 = vcpu->arch.cop0; |
624 | u64 v; | 710 | struct mips_fpu_struct *fpu = &vcpu->arch.fpu; |
711 | s64 v; | ||
712 | s64 vs[2]; | ||
713 | unsigned int idx; | ||
625 | 714 | ||
626 | if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) { | 715 | if ((reg->id & KVM_REG_SIZE_MASK) == KVM_REG_SIZE_U64) { |
627 | u64 __user *uaddr64 = (u64 __user *)(long)reg->addr; | 716 | u64 __user *uaddr64 = (u64 __user *)(long)reg->addr; |
@@ -635,11 +724,16 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, | |||
635 | if (get_user(v32, uaddr32) != 0) | 724 | if (get_user(v32, uaddr32) != 0) |
636 | return -EFAULT; | 725 | return -EFAULT; |
637 | 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); | ||
638 | } else { | 731 | } else { |
639 | return -EINVAL; | 732 | return -EINVAL; |
640 | } | 733 | } |
641 | 734 | ||
642 | switch (reg->id) { | 735 | switch (reg->id) { |
736 | /* General purpose registers */ | ||
643 | case KVM_REG_MIPS_R0: | 737 | case KVM_REG_MIPS_R0: |
644 | /* Silently ignore requests to set $0 */ | 738 | /* Silently ignore requests to set $0 */ |
645 | break; | 739 | break; |
@@ -656,6 +750,64 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, | |||
656 | vcpu->arch.pc = v; | 750 | vcpu->arch.pc = v; |
657 | break; | 751 | break; |
658 | 752 | ||
753 | /* Floating point registers */ | ||
754 | case KVM_REG_MIPS_FPR_32(0) ... KVM_REG_MIPS_FPR_32(31): | ||
755 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
756 | return -EINVAL; | ||
757 | idx = reg->id - KVM_REG_MIPS_FPR_32(0); | ||
758 | /* Odd singles in top of even double when FR=0 */ | ||
759 | if (kvm_read_c0_guest_status(cop0) & ST0_FR) | ||
760 | set_fpr32(&fpu->fpr[idx], 0, v); | ||
761 | else | ||
762 | set_fpr32(&fpu->fpr[idx & ~1], idx & 1, v); | ||
763 | break; | ||
764 | case KVM_REG_MIPS_FPR_64(0) ... KVM_REG_MIPS_FPR_64(31): | ||
765 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
766 | return -EINVAL; | ||
767 | idx = reg->id - KVM_REG_MIPS_FPR_64(0); | ||
768 | /* Can't access odd doubles in FR=0 mode */ | ||
769 | if (idx & 1 && !(kvm_read_c0_guest_status(cop0) & ST0_FR)) | ||
770 | return -EINVAL; | ||
771 | set_fpr64(&fpu->fpr[idx], 0, v); | ||
772 | break; | ||
773 | case KVM_REG_MIPS_FCR_IR: | ||
774 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
775 | return -EINVAL; | ||
776 | /* Read-only */ | ||
777 | break; | ||
778 | case KVM_REG_MIPS_FCR_CSR: | ||
779 | if (!kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
780 | return -EINVAL; | ||
781 | fpu->fcr31 = v; | ||
782 | break; | ||
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 | |||
810 | /* Co-processor 0 registers */ | ||
659 | case KVM_REG_MIPS_CP0_INDEX: | 811 | case KVM_REG_MIPS_CP0_INDEX: |
660 | kvm_write_c0_guest_index(cop0, v); | 812 | kvm_write_c0_guest_index(cop0, v); |
661 | break; | 813 | break; |
@@ -686,6 +838,9 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, | |||
686 | case KVM_REG_MIPS_CP0_EPC: | 838 | case KVM_REG_MIPS_CP0_EPC: |
687 | kvm_write_c0_guest_epc(cop0, v); | 839 | kvm_write_c0_guest_epc(cop0, v); |
688 | break; | 840 | break; |
841 | case KVM_REG_MIPS_CP0_PRID: | ||
842 | kvm_write_c0_guest_prid(cop0, v); | ||
843 | break; | ||
689 | case KVM_REG_MIPS_CP0_ERROREPC: | 844 | case KVM_REG_MIPS_CP0_ERROREPC: |
690 | kvm_write_c0_guest_errorepc(cop0, v); | 845 | kvm_write_c0_guest_errorepc(cop0, v); |
691 | break; | 846 | break; |
@@ -693,6 +848,12 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, | |||
693 | case KVM_REG_MIPS_CP0_COUNT: | 848 | case KVM_REG_MIPS_CP0_COUNT: |
694 | case KVM_REG_MIPS_CP0_COMPARE: | 849 | case KVM_REG_MIPS_CP0_COMPARE: |
695 | case KVM_REG_MIPS_CP0_CAUSE: | 850 | case KVM_REG_MIPS_CP0_CAUSE: |
851 | case KVM_REG_MIPS_CP0_CONFIG: | ||
852 | case KVM_REG_MIPS_CP0_CONFIG1: | ||
853 | case KVM_REG_MIPS_CP0_CONFIG2: | ||
854 | case KVM_REG_MIPS_CP0_CONFIG3: | ||
855 | case KVM_REG_MIPS_CP0_CONFIG4: | ||
856 | case KVM_REG_MIPS_CP0_CONFIG5: | ||
696 | case KVM_REG_MIPS_COUNT_CTL: | 857 | case KVM_REG_MIPS_COUNT_CTL: |
697 | case KVM_REG_MIPS_COUNT_RESUME: | 858 | case KVM_REG_MIPS_COUNT_RESUME: |
698 | case KVM_REG_MIPS_COUNT_HZ: | 859 | case KVM_REG_MIPS_COUNT_HZ: |
@@ -703,6 +864,33 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu, | |||
703 | return 0; | 864 | return 0; |
704 | } | 865 | } |
705 | 866 | ||
867 | static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, | ||
868 | struct kvm_enable_cap *cap) | ||
869 | { | ||
870 | int r = 0; | ||
871 | |||
872 | if (!kvm_vm_ioctl_check_extension(vcpu->kvm, cap->cap)) | ||
873 | return -EINVAL; | ||
874 | if (cap->flags) | ||
875 | return -EINVAL; | ||
876 | if (cap->args[0]) | ||
877 | return -EINVAL; | ||
878 | |||
879 | switch (cap->cap) { | ||
880 | case KVM_CAP_MIPS_FPU: | ||
881 | vcpu->arch.fpu_enabled = true; | ||
882 | break; | ||
883 | case KVM_CAP_MIPS_MSA: | ||
884 | vcpu->arch.msa_enabled = true; | ||
885 | break; | ||
886 | default: | ||
887 | r = -EINVAL; | ||
888 | break; | ||
889 | } | ||
890 | |||
891 | return r; | ||
892 | } | ||
893 | |||
706 | long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, | 894 | long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, |
707 | unsigned long arg) | 895 | unsigned long arg) |
708 | { | 896 | { |
@@ -760,6 +948,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, | |||
760 | r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); | 948 | r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); |
761 | break; | 949 | break; |
762 | } | 950 | } |
951 | case KVM_ENABLE_CAP: { | ||
952 | struct kvm_enable_cap cap; | ||
953 | |||
954 | r = -EFAULT; | ||
955 | if (copy_from_user(&cap, argp, sizeof(cap))) | ||
956 | goto out; | ||
957 | r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); | ||
958 | break; | ||
959 | } | ||
763 | default: | 960 | default: |
764 | r = -ENOIOCTLCMD; | 961 | r = -ENOIOCTLCMD; |
765 | } | 962 | } |
@@ -868,11 +1065,30 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) | |||
868 | 1065 | ||
869 | switch (ext) { | 1066 | switch (ext) { |
870 | case KVM_CAP_ONE_REG: | 1067 | case KVM_CAP_ONE_REG: |
1068 | case KVM_CAP_ENABLE_CAP: | ||
871 | r = 1; | 1069 | r = 1; |
872 | break; | 1070 | break; |
873 | case KVM_CAP_COALESCED_MMIO: | 1071 | case KVM_CAP_COALESCED_MMIO: |
874 | r = KVM_COALESCED_MMIO_PAGE_OFFSET; | 1072 | r = KVM_COALESCED_MMIO_PAGE_OFFSET; |
875 | break; | 1073 | break; |
1074 | case KVM_CAP_MIPS_FPU: | ||
1075 | r = !!cpu_has_fpu; | ||
1076 | break; | ||
1077 | case KVM_CAP_MIPS_MSA: | ||
1078 | /* | ||
1079 | * We don't support MSA vector partitioning yet: | ||
1080 | * 1) It would require explicit support which can't be tested | ||
1081 | * yet due to lack of support in current hardware. | ||
1082 | * 2) It extends the state that would need to be saved/restored | ||
1083 | * by e.g. QEMU for migration. | ||
1084 | * | ||
1085 | * When vector partitioning hardware becomes available, support | ||
1086 | * could be added by requiring a flag when enabling | ||
1087 | * KVM_CAP_MIPS_MSA capability to indicate that userland knows | ||
1088 | * to save/restore the appropriate extra state. | ||
1089 | */ | ||
1090 | r = cpu_has_msa && !(boot_cpu_data.msa_id & MSA_IR_WRPF); | ||
1091 | break; | ||
876 | default: | 1092 | default: |
877 | r = 0; | 1093 | r = 0; |
878 | break; | 1094 | break; |
@@ -1119,6 +1335,30 @@ int kvm_mips_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
1119 | ret = kvm_mips_callbacks->handle_break(vcpu); | 1335 | ret = kvm_mips_callbacks->handle_break(vcpu); |
1120 | break; | 1336 | break; |
1121 | 1337 | ||
1338 | case T_TRAP: | ||
1339 | ++vcpu->stat.trap_inst_exits; | ||
1340 | trace_kvm_exit(vcpu, TRAP_INST_EXITS); | ||
1341 | ret = kvm_mips_callbacks->handle_trap(vcpu); | ||
1342 | break; | ||
1343 | |||
1344 | case T_MSAFPE: | ||
1345 | ++vcpu->stat.msa_fpe_exits; | ||
1346 | trace_kvm_exit(vcpu, MSA_FPE_EXITS); | ||
1347 | ret = kvm_mips_callbacks->handle_msa_fpe(vcpu); | ||
1348 | break; | ||
1349 | |||
1350 | case T_FPE: | ||
1351 | ++vcpu->stat.fpe_exits; | ||
1352 | trace_kvm_exit(vcpu, FPE_EXITS); | ||
1353 | ret = kvm_mips_callbacks->handle_fpe(vcpu); | ||
1354 | break; | ||
1355 | |||
1356 | case T_MSADIS: | ||
1357 | ++vcpu->stat.msa_disabled_exits; | ||
1358 | trace_kvm_exit(vcpu, MSA_DISABLED_EXITS); | ||
1359 | ret = kvm_mips_callbacks->handle_msa_disabled(vcpu); | ||
1360 | break; | ||
1361 | |||
1122 | default: | 1362 | default: |
1123 | kvm_err("Exception Code: %d, not yet handled, @ PC: %p, inst: 0x%08x BadVaddr: %#lx Status: %#lx\n", | 1363 | kvm_err("Exception Code: %d, not yet handled, @ PC: %p, inst: 0x%08x BadVaddr: %#lx Status: %#lx\n", |
1124 | exccode, opc, kvm_get_inst(opc, vcpu), badvaddr, | 1364 | exccode, opc, kvm_get_inst(opc, vcpu), badvaddr, |
@@ -1146,12 +1386,233 @@ skip_emul: | |||
1146 | } | 1386 | } |
1147 | } | 1387 | } |
1148 | 1388 | ||
1389 | if (ret == RESUME_GUEST) { | ||
1390 | /* | ||
1391 | * If FPU / MSA are enabled (i.e. the guest's FPU / MSA context | ||
1392 | * is live), restore FCR31 / MSACSR. | ||
1393 | * | ||
1394 | * This should be before returning to the guest exception | ||
1395 | * vector, as it may well cause an [MSA] FP exception if there | ||
1396 | * are pending exception bits unmasked. (see | ||
1397 | * kvm_mips_csr_die_notifier() for how that is handled). | ||
1398 | */ | ||
1399 | if (kvm_mips_guest_has_fpu(&vcpu->arch) && | ||
1400 | read_c0_status() & ST0_CU1) | ||
1401 | __kvm_restore_fcsr(&vcpu->arch); | ||
1402 | |||
1403 | if (kvm_mips_guest_has_msa(&vcpu->arch) && | ||
1404 | read_c0_config5() & MIPS_CONF5_MSAEN) | ||
1405 | __kvm_restore_msacsr(&vcpu->arch); | ||
1406 | } | ||
1407 | |||
1149 | /* Disable HTW before returning to guest or host */ | 1408 | /* Disable HTW before returning to guest or host */ |
1150 | htw_stop(); | 1409 | htw_stop(); |
1151 | 1410 | ||
1152 | return ret; | 1411 | return ret; |
1153 | } | 1412 | } |
1154 | 1413 | ||
1414 | /* Enable FPU for guest and restore context */ | ||
1415 | void kvm_own_fpu(struct kvm_vcpu *vcpu) | ||
1416 | { | ||
1417 | struct mips_coproc *cop0 = vcpu->arch.cop0; | ||
1418 | unsigned int sr, cfg5; | ||
1419 | |||
1420 | preempt_disable(); | ||
1421 | |||
1422 | sr = kvm_read_c0_guest_status(cop0); | ||
1423 | |||
1424 | /* | ||
1425 | * If MSA state is already live, it is undefined how it interacts with | ||
1426 | * FR=0 FPU state, and we don't want to hit reserved instruction | ||
1427 | * exceptions trying to save the MSA state later when CU=1 && FR=1, so | ||
1428 | * play it safe and save it first. | ||
1429 | * | ||
1430 | * In theory we shouldn't ever hit this case since kvm_lose_fpu() should | ||
1431 | * get called when guest CU1 is set, however we can't trust the guest | ||
1432 | * not to clobber the status register directly via the commpage. | ||
1433 | */ | ||
1434 | if (cpu_has_msa && sr & ST0_CU1 && !(sr & ST0_FR) && | ||
1435 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) | ||
1436 | kvm_lose_fpu(vcpu); | ||
1437 | |||
1438 | /* | ||
1439 | * Enable FPU for guest | ||
1440 | * We set FR and FRE according to guest context | ||
1441 | */ | ||
1442 | change_c0_status(ST0_CU1 | ST0_FR, sr); | ||
1443 | if (cpu_has_fre) { | ||
1444 | cfg5 = kvm_read_c0_guest_config5(cop0); | ||
1445 | change_c0_config5(MIPS_CONF5_FRE, cfg5); | ||
1446 | } | ||
1447 | enable_fpu_hazard(); | ||
1448 | |||
1449 | /* If guest FPU state not active, restore it now */ | ||
1450 | if (!(vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU)) { | ||
1451 | __kvm_restore_fpu(&vcpu->arch); | ||
1452 | vcpu->arch.fpu_inuse |= KVM_MIPS_FPU_FPU; | ||
1453 | } | ||
1454 | |||
1455 | preempt_enable(); | ||
1456 | } | ||
1457 | |||
1458 | #ifdef CONFIG_CPU_HAS_MSA | ||
1459 | /* Enable MSA for guest and restore context */ | ||
1460 | void kvm_own_msa(struct kvm_vcpu *vcpu) | ||
1461 | { | ||
1462 | struct mips_coproc *cop0 = vcpu->arch.cop0; | ||
1463 | unsigned int sr, cfg5; | ||
1464 | |||
1465 | preempt_disable(); | ||
1466 | |||
1467 | /* | ||
1468 | * Enable FPU if enabled in guest, since we're restoring FPU context | ||
1469 | * anyway. We set FR and FRE according to guest context. | ||
1470 | */ | ||
1471 | if (kvm_mips_guest_has_fpu(&vcpu->arch)) { | ||
1472 | sr = kvm_read_c0_guest_status(cop0); | ||
1473 | |||
1474 | /* | ||
1475 | * If FR=0 FPU state is already live, it is undefined how it | ||
1476 | * interacts with MSA state, so play it safe and save it first. | ||
1477 | */ | ||
1478 | if (!(sr & ST0_FR) && | ||
1479 | (vcpu->arch.fpu_inuse & (KVM_MIPS_FPU_FPU | | ||
1480 | KVM_MIPS_FPU_MSA)) == KVM_MIPS_FPU_FPU) | ||
1481 | kvm_lose_fpu(vcpu); | ||
1482 | |||
1483 | change_c0_status(ST0_CU1 | ST0_FR, sr); | ||
1484 | if (sr & ST0_CU1 && cpu_has_fre) { | ||
1485 | cfg5 = kvm_read_c0_guest_config5(cop0); | ||
1486 | change_c0_config5(MIPS_CONF5_FRE, cfg5); | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | /* Enable MSA for guest */ | ||
1491 | set_c0_config5(MIPS_CONF5_MSAEN); | ||
1492 | enable_fpu_hazard(); | ||
1493 | |||
1494 | switch (vcpu->arch.fpu_inuse & (KVM_MIPS_FPU_FPU | KVM_MIPS_FPU_MSA)) { | ||
1495 | case KVM_MIPS_FPU_FPU: | ||
1496 | /* | ||
1497 | * Guest FPU state already loaded, only restore upper MSA state | ||
1498 | */ | ||
1499 | __kvm_restore_msa_upper(&vcpu->arch); | ||
1500 | vcpu->arch.fpu_inuse |= KVM_MIPS_FPU_MSA; | ||
1501 | break; | ||
1502 | case 0: | ||
1503 | /* Neither FPU or MSA already active, restore full MSA state */ | ||
1504 | __kvm_restore_msa(&vcpu->arch); | ||
1505 | vcpu->arch.fpu_inuse |= KVM_MIPS_FPU_MSA; | ||
1506 | if (kvm_mips_guest_has_fpu(&vcpu->arch)) | ||
1507 | vcpu->arch.fpu_inuse |= KVM_MIPS_FPU_FPU; | ||
1508 | break; | ||
1509 | default: | ||
1510 | break; | ||
1511 | } | ||
1512 | |||
1513 | preempt_enable(); | ||
1514 | } | ||
1515 | #endif | ||
1516 | |||
1517 | /* Drop FPU & MSA without saving it */ | ||
1518 | void kvm_drop_fpu(struct kvm_vcpu *vcpu) | ||
1519 | { | ||
1520 | preempt_disable(); | ||
1521 | if (cpu_has_msa && vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) { | ||
1522 | disable_msa(); | ||
1523 | vcpu->arch.fpu_inuse &= ~KVM_MIPS_FPU_MSA; | ||
1524 | } | ||
1525 | if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) { | ||
1526 | clear_c0_status(ST0_CU1 | ST0_FR); | ||
1527 | vcpu->arch.fpu_inuse &= ~KVM_MIPS_FPU_FPU; | ||
1528 | } | ||
1529 | preempt_enable(); | ||
1530 | } | ||
1531 | |||
1532 | /* Save and disable FPU & MSA */ | ||
1533 | void kvm_lose_fpu(struct kvm_vcpu *vcpu) | ||
1534 | { | ||
1535 | /* | ||
1536 | * FPU & MSA get disabled in root context (hardware) when it is disabled | ||
1537 | * in guest context (software), but the register state in the hardware | ||
1538 | * may still be in use. This is why we explicitly re-enable the hardware | ||
1539 | * before saving. | ||
1540 | */ | ||
1541 | |||
1542 | preempt_disable(); | ||
1543 | if (cpu_has_msa && vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) { | ||
1544 | set_c0_config5(MIPS_CONF5_MSAEN); | ||
1545 | enable_fpu_hazard(); | ||
1546 | |||
1547 | __kvm_save_msa(&vcpu->arch); | ||
1548 | |||
1549 | /* Disable MSA & FPU */ | ||
1550 | disable_msa(); | ||
1551 | if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) | ||
1552 | clear_c0_status(ST0_CU1 | ST0_FR); | ||
1553 | vcpu->arch.fpu_inuse &= ~(KVM_MIPS_FPU_FPU | KVM_MIPS_FPU_MSA); | ||
1554 | } else if (vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) { | ||
1555 | set_c0_status(ST0_CU1); | ||
1556 | enable_fpu_hazard(); | ||
1557 | |||
1558 | __kvm_save_fpu(&vcpu->arch); | ||
1559 | vcpu->arch.fpu_inuse &= ~KVM_MIPS_FPU_FPU; | ||
1560 | |||
1561 | /* Disable FPU */ | ||
1562 | clear_c0_status(ST0_CU1 | ST0_FR); | ||
1563 | } | ||
1564 | preempt_enable(); | ||
1565 | } | ||
1566 | |||
1567 | /* | ||
1568 | * Step over a specific ctc1 to FCSR and a specific ctcmsa to MSACSR which are | ||
1569 | * used to restore guest FCSR/MSACSR state and may trigger a "harmless" FP/MSAFP | ||
1570 | * exception if cause bits are set in the value being written. | ||
1571 | */ | ||
1572 | static int kvm_mips_csr_die_notify(struct notifier_block *self, | ||
1573 | unsigned long cmd, void *ptr) | ||
1574 | { | ||
1575 | struct die_args *args = (struct die_args *)ptr; | ||
1576 | struct pt_regs *regs = args->regs; | ||
1577 | unsigned long pc; | ||
1578 | |||
1579 | /* Only interested in FPE and MSAFPE */ | ||
1580 | if (cmd != DIE_FP && cmd != DIE_MSAFP) | ||
1581 | return NOTIFY_DONE; | ||
1582 | |||
1583 | /* Return immediately if guest context isn't active */ | ||
1584 | if (!(current->flags & PF_VCPU)) | ||
1585 | return NOTIFY_DONE; | ||
1586 | |||
1587 | /* Should never get here from user mode */ | ||
1588 | BUG_ON(user_mode(regs)); | ||
1589 | |||
1590 | pc = instruction_pointer(regs); | ||
1591 | switch (cmd) { | ||
1592 | case DIE_FP: | ||
1593 | /* match 2nd instruction in __kvm_restore_fcsr */ | ||
1594 | if (pc != (unsigned long)&__kvm_restore_fcsr + 4) | ||
1595 | return NOTIFY_DONE; | ||
1596 | break; | ||
1597 | case DIE_MSAFP: | ||
1598 | /* match 2nd/3rd instruction in __kvm_restore_msacsr */ | ||
1599 | if (!cpu_has_msa || | ||
1600 | pc < (unsigned long)&__kvm_restore_msacsr + 4 || | ||
1601 | pc > (unsigned long)&__kvm_restore_msacsr + 8) | ||
1602 | return NOTIFY_DONE; | ||
1603 | break; | ||
1604 | } | ||
1605 | |||
1606 | /* Move PC forward a little and continue executing */ | ||
1607 | instruction_pointer(regs) += 4; | ||
1608 | |||
1609 | return NOTIFY_STOP; | ||
1610 | } | ||
1611 | |||
1612 | static struct notifier_block kvm_mips_csr_die_notifier = { | ||
1613 | .notifier_call = kvm_mips_csr_die_notify, | ||
1614 | }; | ||
1615 | |||
1155 | int __init kvm_mips_init(void) | 1616 | int __init kvm_mips_init(void) |
1156 | { | 1617 | { |
1157 | int ret; | 1618 | int ret; |
@@ -1161,6 +1622,8 @@ int __init kvm_mips_init(void) | |||
1161 | if (ret) | 1622 | if (ret) |
1162 | return ret; | 1623 | return ret; |
1163 | 1624 | ||
1625 | register_die_notifier(&kvm_mips_csr_die_notifier); | ||
1626 | |||
1164 | /* | 1627 | /* |
1165 | * On MIPS, kernel modules are executed from "mapped space", which | 1628 | * On MIPS, kernel modules are executed from "mapped space", which |
1166 | * requires TLBs. The TLB handling code is statically linked with | 1629 | * requires TLBs. The TLB handling code is statically linked with |
@@ -1173,7 +1636,6 @@ int __init kvm_mips_init(void) | |||
1173 | kvm_mips_release_pfn_clean = kvm_release_pfn_clean; | 1636 | kvm_mips_release_pfn_clean = kvm_release_pfn_clean; |
1174 | kvm_mips_is_error_pfn = is_error_pfn; | 1637 | kvm_mips_is_error_pfn = is_error_pfn; |
1175 | 1638 | ||
1176 | pr_info("KVM/MIPS Initialized\n"); | ||
1177 | return 0; | 1639 | return 0; |
1178 | } | 1640 | } |
1179 | 1641 | ||
@@ -1185,7 +1647,7 @@ void __exit kvm_mips_exit(void) | |||
1185 | kvm_mips_release_pfn_clean = NULL; | 1647 | kvm_mips_release_pfn_clean = NULL; |
1186 | kvm_mips_is_error_pfn = NULL; | 1648 | kvm_mips_is_error_pfn = NULL; |
1187 | 1649 | ||
1188 | pr_info("KVM/MIPS unloaded\n"); | 1650 | unregister_die_notifier(&kvm_mips_csr_die_notifier); |
1189 | } | 1651 | } |
1190 | 1652 | ||
1191 | module_init(kvm_mips_init); | 1653 | module_init(kvm_mips_init); |
diff --git a/arch/mips/kvm/msa.S b/arch/mips/kvm/msa.S new file mode 100644 index 000000000000..d02f0c6cc2cc --- /dev/null +++ b/arch/mips/kvm/msa.S | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * MIPS SIMD Architecture (MSA) context handling code for KVM. | ||
7 | * | ||
8 | * Copyright (C) 2015 Imagination Technologies Ltd. | ||
9 | */ | ||
10 | |||
11 | #include <asm/asm.h> | ||
12 | #include <asm/asm-offsets.h> | ||
13 | #include <asm/asmmacro.h> | ||
14 | #include <asm/regdef.h> | ||
15 | |||
16 | .set noreorder | ||
17 | .set noat | ||
18 | |||
19 | LEAF(__kvm_save_msa) | ||
20 | st_d 0, VCPU_FPR0, a0 | ||
21 | st_d 1, VCPU_FPR1, a0 | ||
22 | st_d 2, VCPU_FPR2, a0 | ||
23 | st_d 3, VCPU_FPR3, a0 | ||
24 | st_d 4, VCPU_FPR4, a0 | ||
25 | st_d 5, VCPU_FPR5, a0 | ||
26 | st_d 6, VCPU_FPR6, a0 | ||
27 | st_d 7, VCPU_FPR7, a0 | ||
28 | st_d 8, VCPU_FPR8, a0 | ||
29 | st_d 9, VCPU_FPR9, a0 | ||
30 | st_d 10, VCPU_FPR10, a0 | ||
31 | st_d 11, VCPU_FPR11, a0 | ||
32 | st_d 12, VCPU_FPR12, a0 | ||
33 | st_d 13, VCPU_FPR13, a0 | ||
34 | st_d 14, VCPU_FPR14, a0 | ||
35 | st_d 15, VCPU_FPR15, a0 | ||
36 | st_d 16, VCPU_FPR16, a0 | ||
37 | st_d 17, VCPU_FPR17, a0 | ||
38 | st_d 18, VCPU_FPR18, a0 | ||
39 | st_d 19, VCPU_FPR19, a0 | ||
40 | st_d 20, VCPU_FPR20, a0 | ||
41 | st_d 21, VCPU_FPR21, a0 | ||
42 | st_d 22, VCPU_FPR22, a0 | ||
43 | st_d 23, VCPU_FPR23, a0 | ||
44 | st_d 24, VCPU_FPR24, a0 | ||
45 | st_d 25, VCPU_FPR25, a0 | ||
46 | st_d 26, VCPU_FPR26, a0 | ||
47 | st_d 27, VCPU_FPR27, a0 | ||
48 | st_d 28, VCPU_FPR28, a0 | ||
49 | st_d 29, VCPU_FPR29, a0 | ||
50 | st_d 30, VCPU_FPR30, a0 | ||
51 | st_d 31, VCPU_FPR31, a0 | ||
52 | jr ra | ||
53 | nop | ||
54 | END(__kvm_save_msa) | ||
55 | |||
56 | LEAF(__kvm_restore_msa) | ||
57 | ld_d 0, VCPU_FPR0, a0 | ||
58 | ld_d 1, VCPU_FPR1, a0 | ||
59 | ld_d 2, VCPU_FPR2, a0 | ||
60 | ld_d 3, VCPU_FPR3, a0 | ||
61 | ld_d 4, VCPU_FPR4, a0 | ||
62 | ld_d 5, VCPU_FPR5, a0 | ||
63 | ld_d 6, VCPU_FPR6, a0 | ||
64 | ld_d 7, VCPU_FPR7, a0 | ||
65 | ld_d 8, VCPU_FPR8, a0 | ||
66 | ld_d 9, VCPU_FPR9, a0 | ||
67 | ld_d 10, VCPU_FPR10, a0 | ||
68 | ld_d 11, VCPU_FPR11, a0 | ||
69 | ld_d 12, VCPU_FPR12, a0 | ||
70 | ld_d 13, VCPU_FPR13, a0 | ||
71 | ld_d 14, VCPU_FPR14, a0 | ||
72 | ld_d 15, VCPU_FPR15, a0 | ||
73 | ld_d 16, VCPU_FPR16, a0 | ||
74 | ld_d 17, VCPU_FPR17, a0 | ||
75 | ld_d 18, VCPU_FPR18, a0 | ||
76 | ld_d 19, VCPU_FPR19, a0 | ||
77 | ld_d 20, VCPU_FPR20, a0 | ||
78 | ld_d 21, VCPU_FPR21, a0 | ||
79 | ld_d 22, VCPU_FPR22, a0 | ||
80 | ld_d 23, VCPU_FPR23, a0 | ||
81 | ld_d 24, VCPU_FPR24, a0 | ||
82 | ld_d 25, VCPU_FPR25, a0 | ||
83 | ld_d 26, VCPU_FPR26, a0 | ||
84 | ld_d 27, VCPU_FPR27, a0 | ||
85 | ld_d 28, VCPU_FPR28, a0 | ||
86 | ld_d 29, VCPU_FPR29, a0 | ||
87 | ld_d 30, VCPU_FPR30, a0 | ||
88 | ld_d 31, VCPU_FPR31, a0 | ||
89 | jr ra | ||
90 | nop | ||
91 | END(__kvm_restore_msa) | ||
92 | |||
93 | .macro kvm_restore_msa_upper wr, off, base | ||
94 | .set push | ||
95 | .set noat | ||
96 | #ifdef CONFIG_64BIT | ||
97 | ld $1, \off(\base) | ||
98 | insert_d \wr, 1 | ||
99 | #elif defined(CONFIG_CPU_LITTLE_ENDIAN) | ||
100 | lw $1, \off(\base) | ||
101 | insert_w \wr, 2 | ||
102 | lw $1, (\off+4)(\base) | ||
103 | insert_w \wr, 3 | ||
104 | #else /* CONFIG_CPU_BIG_ENDIAN */ | ||
105 | lw $1, (\off+4)(\base) | ||
106 | insert_w \wr, 2 | ||
107 | lw $1, \off(\base) | ||
108 | insert_w \wr, 3 | ||
109 | #endif | ||
110 | .set pop | ||
111 | .endm | ||
112 | |||
113 | LEAF(__kvm_restore_msa_upper) | ||
114 | kvm_restore_msa_upper 0, VCPU_FPR0 +8, a0 | ||
115 | kvm_restore_msa_upper 1, VCPU_FPR1 +8, a0 | ||
116 | kvm_restore_msa_upper 2, VCPU_FPR2 +8, a0 | ||
117 | kvm_restore_msa_upper 3, VCPU_FPR3 +8, a0 | ||
118 | kvm_restore_msa_upper 4, VCPU_FPR4 +8, a0 | ||
119 | kvm_restore_msa_upper 5, VCPU_FPR5 +8, a0 | ||
120 | kvm_restore_msa_upper 6, VCPU_FPR6 +8, a0 | ||
121 | kvm_restore_msa_upper 7, VCPU_FPR7 +8, a0 | ||
122 | kvm_restore_msa_upper 8, VCPU_FPR8 +8, a0 | ||
123 | kvm_restore_msa_upper 9, VCPU_FPR9 +8, a0 | ||
124 | kvm_restore_msa_upper 10, VCPU_FPR10+8, a0 | ||
125 | kvm_restore_msa_upper 11, VCPU_FPR11+8, a0 | ||
126 | kvm_restore_msa_upper 12, VCPU_FPR12+8, a0 | ||
127 | kvm_restore_msa_upper 13, VCPU_FPR13+8, a0 | ||
128 | kvm_restore_msa_upper 14, VCPU_FPR14+8, a0 | ||
129 | kvm_restore_msa_upper 15, VCPU_FPR15+8, a0 | ||
130 | kvm_restore_msa_upper 16, VCPU_FPR16+8, a0 | ||
131 | kvm_restore_msa_upper 17, VCPU_FPR17+8, a0 | ||
132 | kvm_restore_msa_upper 18, VCPU_FPR18+8, a0 | ||
133 | kvm_restore_msa_upper 19, VCPU_FPR19+8, a0 | ||
134 | kvm_restore_msa_upper 20, VCPU_FPR20+8, a0 | ||
135 | kvm_restore_msa_upper 21, VCPU_FPR21+8, a0 | ||
136 | kvm_restore_msa_upper 22, VCPU_FPR22+8, a0 | ||
137 | kvm_restore_msa_upper 23, VCPU_FPR23+8, a0 | ||
138 | kvm_restore_msa_upper 24, VCPU_FPR24+8, a0 | ||
139 | kvm_restore_msa_upper 25, VCPU_FPR25+8, a0 | ||
140 | kvm_restore_msa_upper 26, VCPU_FPR26+8, a0 | ||
141 | kvm_restore_msa_upper 27, VCPU_FPR27+8, a0 | ||
142 | kvm_restore_msa_upper 28, VCPU_FPR28+8, a0 | ||
143 | kvm_restore_msa_upper 29, VCPU_FPR29+8, a0 | ||
144 | kvm_restore_msa_upper 30, VCPU_FPR30+8, a0 | ||
145 | kvm_restore_msa_upper 31, VCPU_FPR31+8, a0 | ||
146 | jr ra | ||
147 | nop | ||
148 | END(__kvm_restore_msa_upper) | ||
149 | |||
150 | LEAF(__kvm_restore_msacsr) | ||
151 | lw t0, VCPU_MSA_CSR(a0) | ||
152 | /* | ||
153 | * The ctcmsa must stay at this offset in __kvm_restore_msacsr. | ||
154 | * See kvm_mips_csr_die_notify() which handles t0 containing a value | ||
155 | * which triggers an MSA FP Exception, which must be stepped over and | ||
156 | * ignored since the set cause bits must remain there for the guest. | ||
157 | */ | ||
158 | _ctcmsa MSA_CSR, t0 | ||
159 | jr ra | ||
160 | nop | ||
161 | END(__kvm_restore_msacsr) | ||
diff --git a/arch/mips/kvm/stats.c b/arch/mips/kvm/stats.c index a74d6024c5ad..888bb67070ac 100644 --- a/arch/mips/kvm/stats.c +++ b/arch/mips/kvm/stats.c | |||
@@ -25,6 +25,10 @@ char *kvm_mips_exit_types_str[MAX_KVM_MIPS_EXIT_TYPES] = { | |||
25 | "System Call", | 25 | "System Call", |
26 | "Reserved Inst", | 26 | "Reserved Inst", |
27 | "Break Inst", | 27 | "Break Inst", |
28 | "Trap Inst", | ||
29 | "MSA FPE", | ||
30 | "FPE", | ||
31 | "MSA Disabled", | ||
28 | "D-Cache Flushes", | 32 | "D-Cache Flushes", |
29 | }; | 33 | }; |
30 | 34 | ||
diff --git a/arch/mips/kvm/tlb.c b/arch/mips/kvm/tlb.c index b6beb0e07b1b..aed0ac2a4972 100644 --- a/arch/mips/kvm/tlb.c +++ b/arch/mips/kvm/tlb.c | |||
@@ -733,6 +733,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |||
733 | } | 733 | } |
734 | } | 734 | } |
735 | 735 | ||
736 | /* restore guest state to registers */ | ||
737 | kvm_mips_callbacks->vcpu_set_regs(vcpu); | ||
738 | |||
736 | local_irq_restore(flags); | 739 | local_irq_restore(flags); |
737 | 740 | ||
738 | } | 741 | } |
@@ -751,6 +754,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) | |||
751 | vcpu->arch.preempt_entryhi = read_c0_entryhi(); | 754 | vcpu->arch.preempt_entryhi = read_c0_entryhi(); |
752 | vcpu->arch.last_sched_cpu = cpu; | 755 | vcpu->arch.last_sched_cpu = cpu; |
753 | 756 | ||
757 | /* save guest state in registers */ | ||
758 | kvm_mips_callbacks->vcpu_get_regs(vcpu); | ||
759 | |||
754 | if (((cpu_context(cpu, current->mm) ^ asid_cache(cpu)) & | 760 | if (((cpu_context(cpu, current->mm) ^ asid_cache(cpu)) & |
755 | ASID_VERSION_MASK)) { | 761 | ASID_VERSION_MASK)) { |
756 | kvm_debug("%s: Dropping MMU Context: %#lx\n", __func__, | 762 | kvm_debug("%s: Dropping MMU Context: %#lx\n", __func__, |
diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c index fd7257b70e65..d836ed5b0bc7 100644 --- a/arch/mips/kvm/trap_emul.c +++ b/arch/mips/kvm/trap_emul.c | |||
@@ -39,16 +39,30 @@ static gpa_t kvm_trap_emul_gva_to_gpa_cb(gva_t gva) | |||
39 | 39 | ||
40 | static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu) | 40 | static int kvm_trap_emul_handle_cop_unusable(struct kvm_vcpu *vcpu) |
41 | { | 41 | { |
42 | struct mips_coproc *cop0 = vcpu->arch.cop0; | ||
42 | struct kvm_run *run = vcpu->run; | 43 | struct kvm_run *run = vcpu->run; |
43 | uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc; | 44 | uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc; |
44 | unsigned long cause = vcpu->arch.host_cp0_cause; | 45 | unsigned long cause = vcpu->arch.host_cp0_cause; |
45 | enum emulation_result er = EMULATE_DONE; | 46 | enum emulation_result er = EMULATE_DONE; |
46 | int ret = RESUME_GUEST; | 47 | int ret = RESUME_GUEST; |
47 | 48 | ||
48 | if (((cause & CAUSEF_CE) >> CAUSEB_CE) == 1) | 49 | if (((cause & CAUSEF_CE) >> CAUSEB_CE) == 1) { |
49 | er = kvm_mips_emulate_fpu_exc(cause, opc, run, vcpu); | 50 | /* FPU Unusable */ |
50 | else | 51 | if (!kvm_mips_guest_has_fpu(&vcpu->arch) || |
52 | (kvm_read_c0_guest_status(cop0) & ST0_CU1) == 0) { | ||
53 | /* | ||
54 | * Unusable/no FPU in guest: | ||
55 | * deliver guest COP1 Unusable Exception | ||
56 | */ | ||
57 | er = kvm_mips_emulate_fpu_exc(cause, opc, run, vcpu); | ||
58 | } else { | ||
59 | /* Restore FPU state */ | ||
60 | kvm_own_fpu(vcpu); | ||
61 | er = EMULATE_DONE; | ||
62 | } | ||
63 | } else { | ||
51 | er = kvm_mips_emulate_inst(cause, opc, run, vcpu); | 64 | er = kvm_mips_emulate_inst(cause, opc, run, vcpu); |
65 | } | ||
52 | 66 | ||
53 | switch (er) { | 67 | switch (er) { |
54 | case EMULATE_DONE: | 68 | case EMULATE_DONE: |
@@ -330,6 +344,107 @@ static int kvm_trap_emul_handle_break(struct kvm_vcpu *vcpu) | |||
330 | return ret; | 344 | return ret; |
331 | } | 345 | } |
332 | 346 | ||
347 | static int kvm_trap_emul_handle_trap(struct kvm_vcpu *vcpu) | ||
348 | { | ||
349 | struct kvm_run *run = vcpu->run; | ||
350 | uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc; | ||
351 | unsigned long cause = vcpu->arch.host_cp0_cause; | ||
352 | enum emulation_result er = EMULATE_DONE; | ||
353 | int ret = RESUME_GUEST; | ||
354 | |||
355 | er = kvm_mips_emulate_trap_exc(cause, opc, run, vcpu); | ||
356 | if (er == EMULATE_DONE) { | ||
357 | ret = RESUME_GUEST; | ||
358 | } else { | ||
359 | run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | ||
360 | ret = RESUME_HOST; | ||
361 | } | ||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | static int kvm_trap_emul_handle_msa_fpe(struct kvm_vcpu *vcpu) | ||
366 | { | ||
367 | struct kvm_run *run = vcpu->run; | ||
368 | uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc; | ||
369 | unsigned long cause = vcpu->arch.host_cp0_cause; | ||
370 | enum emulation_result er = EMULATE_DONE; | ||
371 | int ret = RESUME_GUEST; | ||
372 | |||
373 | er = kvm_mips_emulate_msafpe_exc(cause, opc, run, vcpu); | ||
374 | if (er == EMULATE_DONE) { | ||
375 | ret = RESUME_GUEST; | ||
376 | } else { | ||
377 | run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | ||
378 | ret = RESUME_HOST; | ||
379 | } | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | static int kvm_trap_emul_handle_fpe(struct kvm_vcpu *vcpu) | ||
384 | { | ||
385 | struct kvm_run *run = vcpu->run; | ||
386 | uint32_t __user *opc = (uint32_t __user *)vcpu->arch.pc; | ||
387 | unsigned long cause = vcpu->arch.host_cp0_cause; | ||
388 | enum emulation_result er = EMULATE_DONE; | ||
389 | int ret = RESUME_GUEST; | ||
390 | |||
391 | er = kvm_mips_emulate_fpe_exc(cause, opc, run, vcpu); | ||
392 | if (er == EMULATE_DONE) { | ||
393 | ret = RESUME_GUEST; | ||
394 | } else { | ||
395 | run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | ||
396 | ret = RESUME_HOST; | ||
397 | } | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * kvm_trap_emul_handle_msa_disabled() - Guest used MSA while disabled in root. | ||
403 | * @vcpu: Virtual CPU context. | ||
404 | * | ||
405 | * Handle when the guest attempts to use MSA when it is disabled. | ||
406 | */ | ||
407 | static int kvm_trap_emul_handle_msa_disabled(struct kvm_vcpu *vcpu) | ||
408 | { | ||
409 | struct mips_coproc *cop0 = vcpu->arch.cop0; | ||
410 | struct kvm_run *run = vcpu->run; | ||
411 | uint32_t __user *opc = (uint32_t __user *) vcpu->arch.pc; | ||
412 | unsigned long cause = vcpu->arch.host_cp0_cause; | ||
413 | enum emulation_result er = EMULATE_DONE; | ||
414 | int ret = RESUME_GUEST; | ||
415 | |||
416 | if (!kvm_mips_guest_has_msa(&vcpu->arch) || | ||
417 | (kvm_read_c0_guest_status(cop0) & (ST0_CU1 | ST0_FR)) == ST0_CU1) { | ||
418 | /* | ||
419 | * No MSA in guest, or FPU enabled and not in FR=1 mode, | ||
420 | * guest reserved instruction exception | ||
421 | */ | ||
422 | er = kvm_mips_emulate_ri_exc(cause, opc, run, vcpu); | ||
423 | } else if (!(kvm_read_c0_guest_config5(cop0) & MIPS_CONF5_MSAEN)) { | ||
424 | /* MSA disabled by guest, guest MSA disabled exception */ | ||
425 | er = kvm_mips_emulate_msadis_exc(cause, opc, run, vcpu); | ||
426 | } else { | ||
427 | /* Restore MSA/FPU state */ | ||
428 | kvm_own_msa(vcpu); | ||
429 | er = EMULATE_DONE; | ||
430 | } | ||
431 | |||
432 | switch (er) { | ||
433 | case EMULATE_DONE: | ||
434 | ret = RESUME_GUEST; | ||
435 | break; | ||
436 | |||
437 | case EMULATE_FAIL: | ||
438 | run->exit_reason = KVM_EXIT_INTERNAL_ERROR; | ||
439 | ret = RESUME_HOST; | ||
440 | break; | ||
441 | |||
442 | default: | ||
443 | BUG(); | ||
444 | } | ||
445 | return ret; | ||
446 | } | ||
447 | |||
333 | static int kvm_trap_emul_vm_init(struct kvm *kvm) | 448 | static int kvm_trap_emul_vm_init(struct kvm *kvm) |
334 | { | 449 | { |
335 | return 0; | 450 | return 0; |
@@ -351,8 +466,9 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu) | |||
351 | * guest will come up as expected, for now we simulate a MIPS 24kc | 466 | * guest will come up as expected, for now we simulate a MIPS 24kc |
352 | */ | 467 | */ |
353 | kvm_write_c0_guest_prid(cop0, 0x00019300); | 468 | kvm_write_c0_guest_prid(cop0, 0x00019300); |
354 | kvm_write_c0_guest_config(cop0, | 469 | /* Have config1, Cacheable, noncoherent, write-back, write allocate */ |
355 | MIPS_CONFIG0 | (0x1 << CP0C0_AR) | | 470 | kvm_write_c0_guest_config(cop0, MIPS_CONF_M | (0x3 << CP0C0_K0) | |
471 | (0x1 << CP0C0_AR) | | ||
356 | (MMU_TYPE_R4000 << CP0C0_MT)); | 472 | (MMU_TYPE_R4000 << CP0C0_MT)); |
357 | 473 | ||
358 | /* Read the cache characteristics from the host Config1 Register */ | 474 | /* Read the cache characteristics from the host Config1 Register */ |
@@ -368,10 +484,18 @@ static int kvm_trap_emul_vcpu_setup(struct kvm_vcpu *vcpu) | |||
368 | (1 << CP0C1_WR) | (1 << CP0C1_CA)); | 484 | (1 << CP0C1_WR) | (1 << CP0C1_CA)); |
369 | kvm_write_c0_guest_config1(cop0, config1); | 485 | kvm_write_c0_guest_config1(cop0, config1); |
370 | 486 | ||
371 | kvm_write_c0_guest_config2(cop0, MIPS_CONFIG2); | 487 | /* Have config3, no tertiary/secondary caches implemented */ |
372 | /* MIPS_CONFIG2 | (read_c0_config2() & 0xfff) */ | 488 | kvm_write_c0_guest_config2(cop0, MIPS_CONF_M); |
373 | kvm_write_c0_guest_config3(cop0, MIPS_CONFIG3 | (0 << CP0C3_VInt) | | 489 | /* MIPS_CONF_M | (read_c0_config2() & 0xfff) */ |
374 | (1 << CP0C3_ULRI)); | 490 | |
491 | /* Have config4, UserLocal */ | ||
492 | kvm_write_c0_guest_config3(cop0, MIPS_CONF_M | MIPS_CONF3_ULRI); | ||
493 | |||
494 | /* Have config5 */ | ||
495 | kvm_write_c0_guest_config4(cop0, MIPS_CONF_M); | ||
496 | |||
497 | /* No config6 */ | ||
498 | kvm_write_c0_guest_config5(cop0, 0); | ||
375 | 499 | ||
376 | /* Set Wait IE/IXMT Ignore in Config7, IAR, AR */ | 500 | /* Set Wait IE/IXMT Ignore in Config7, IAR, AR */ |
377 | kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10)); | 501 | kvm_write_c0_guest_config7(cop0, (MIPS_CONF7_WII) | (1 << 10)); |
@@ -416,6 +540,7 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu, | |||
416 | { | 540 | { |
417 | struct mips_coproc *cop0 = vcpu->arch.cop0; | 541 | struct mips_coproc *cop0 = vcpu->arch.cop0; |
418 | int ret = 0; | 542 | int ret = 0; |
543 | unsigned int cur, change; | ||
419 | 544 | ||
420 | switch (reg->id) { | 545 | switch (reg->id) { |
421 | case KVM_REG_MIPS_CP0_COUNT: | 546 | case KVM_REG_MIPS_CP0_COUNT: |
@@ -444,6 +569,44 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu, | |||
444 | kvm_write_c0_guest_cause(cop0, v); | 569 | kvm_write_c0_guest_cause(cop0, v); |
445 | } | 570 | } |
446 | break; | 571 | break; |
572 | case KVM_REG_MIPS_CP0_CONFIG: | ||
573 | /* read-only for now */ | ||
574 | break; | ||
575 | case KVM_REG_MIPS_CP0_CONFIG1: | ||
576 | cur = kvm_read_c0_guest_config1(cop0); | ||
577 | change = (cur ^ v) & kvm_mips_config1_wrmask(vcpu); | ||
578 | if (change) { | ||
579 | v = cur ^ change; | ||
580 | kvm_write_c0_guest_config1(cop0, v); | ||
581 | } | ||
582 | break; | ||
583 | case KVM_REG_MIPS_CP0_CONFIG2: | ||
584 | /* read-only for now */ | ||
585 | break; | ||
586 | case KVM_REG_MIPS_CP0_CONFIG3: | ||
587 | cur = kvm_read_c0_guest_config3(cop0); | ||
588 | change = (cur ^ v) & kvm_mips_config3_wrmask(vcpu); | ||
589 | if (change) { | ||
590 | v = cur ^ change; | ||
591 | kvm_write_c0_guest_config3(cop0, v); | ||
592 | } | ||
593 | break; | ||
594 | case KVM_REG_MIPS_CP0_CONFIG4: | ||
595 | cur = kvm_read_c0_guest_config4(cop0); | ||
596 | change = (cur ^ v) & kvm_mips_config4_wrmask(vcpu); | ||
597 | if (change) { | ||
598 | v = cur ^ change; | ||
599 | kvm_write_c0_guest_config4(cop0, v); | ||
600 | } | ||
601 | break; | ||
602 | case KVM_REG_MIPS_CP0_CONFIG5: | ||
603 | cur = kvm_read_c0_guest_config5(cop0); | ||
604 | change = (cur ^ v) & kvm_mips_config5_wrmask(vcpu); | ||
605 | if (change) { | ||
606 | v = cur ^ change; | ||
607 | kvm_write_c0_guest_config5(cop0, v); | ||
608 | } | ||
609 | break; | ||
447 | case KVM_REG_MIPS_COUNT_CTL: | 610 | case KVM_REG_MIPS_COUNT_CTL: |
448 | ret = kvm_mips_set_count_ctl(vcpu, v); | 611 | ret = kvm_mips_set_count_ctl(vcpu, v); |
449 | break; | 612 | break; |
@@ -459,6 +622,18 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu, | |||
459 | return ret; | 622 | return ret; |
460 | } | 623 | } |
461 | 624 | ||
625 | static int kvm_trap_emul_vcpu_get_regs(struct kvm_vcpu *vcpu) | ||
626 | { | ||
627 | kvm_lose_fpu(vcpu); | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static int kvm_trap_emul_vcpu_set_regs(struct kvm_vcpu *vcpu) | ||
633 | { | ||
634 | return 0; | ||
635 | } | ||
636 | |||
462 | static struct kvm_mips_callbacks kvm_trap_emul_callbacks = { | 637 | static struct kvm_mips_callbacks kvm_trap_emul_callbacks = { |
463 | /* exit handlers */ | 638 | /* exit handlers */ |
464 | .handle_cop_unusable = kvm_trap_emul_handle_cop_unusable, | 639 | .handle_cop_unusable = kvm_trap_emul_handle_cop_unusable, |
@@ -470,6 +645,10 @@ static struct kvm_mips_callbacks kvm_trap_emul_callbacks = { | |||
470 | .handle_syscall = kvm_trap_emul_handle_syscall, | 645 | .handle_syscall = kvm_trap_emul_handle_syscall, |
471 | .handle_res_inst = kvm_trap_emul_handle_res_inst, | 646 | .handle_res_inst = kvm_trap_emul_handle_res_inst, |
472 | .handle_break = kvm_trap_emul_handle_break, | 647 | .handle_break = kvm_trap_emul_handle_break, |
648 | .handle_trap = kvm_trap_emul_handle_trap, | ||
649 | .handle_msa_fpe = kvm_trap_emul_handle_msa_fpe, | ||
650 | .handle_fpe = kvm_trap_emul_handle_fpe, | ||
651 | .handle_msa_disabled = kvm_trap_emul_handle_msa_disabled, | ||
473 | 652 | ||
474 | .vm_init = kvm_trap_emul_vm_init, | 653 | .vm_init = kvm_trap_emul_vm_init, |
475 | .vcpu_init = kvm_trap_emul_vcpu_init, | 654 | .vcpu_init = kvm_trap_emul_vcpu_init, |
@@ -483,6 +662,8 @@ static struct kvm_mips_callbacks kvm_trap_emul_callbacks = { | |||
483 | .irq_clear = kvm_mips_irq_clear_cb, | 662 | .irq_clear = kvm_mips_irq_clear_cb, |
484 | .get_one_reg = kvm_trap_emul_get_one_reg, | 663 | .get_one_reg = kvm_trap_emul_get_one_reg, |
485 | .set_one_reg = kvm_trap_emul_set_one_reg, | 664 | .set_one_reg = kvm_trap_emul_set_one_reg, |
665 | .vcpu_get_regs = kvm_trap_emul_vcpu_get_regs, | ||
666 | .vcpu_set_regs = kvm_trap_emul_vcpu_set_regs, | ||
486 | }; | 667 | }; |
487 | 668 | ||
488 | int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks) | 669 | int kvm_mips_emulation_init(struct kvm_mips_callbacks **install_callbacks) |