Commit | Line | Data |
---|---|---|
d0c7dc03 HB |
1 | /* |
2 | * This program is free software; you can redistribute it and/or modify | |
3 | * it under the terms of the GNU General Public License, version 2, as | |
4 | * published by the Free Software Foundation. | |
5 | * | |
6 | * This program is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
9 | * GNU General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU General Public License | |
12 | * along with this program; if not, write to the Free Software | |
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
14 | * | |
15 | * Copyright IBM Corp. 2008 | |
16 | * | |
17 | * Authors: Hollis Blanchard <hollisb@us.ibm.com> | |
18 | */ | |
19 | ||
20 | #include <linux/kvm_host.h> | |
21 | #include <asm/disassemble.h> | |
22 | ||
23 | #include "booke.h" | |
24 | ||
25 | #define OP_19_XOP_RFI 50 | |
26 | ||
27 | #define OP_31_XOP_MFMSR 83 | |
28 | #define OP_31_XOP_WRTEE 131 | |
29 | #define OP_31_XOP_MTMSR 146 | |
30 | #define OP_31_XOP_WRTEEI 163 | |
31 | ||
32 | static void kvmppc_emul_rfi(struct kvm_vcpu *vcpu) | |
33 | { | |
34 | vcpu->arch.pc = vcpu->arch.srr0; | |
35 | kvmppc_set_msr(vcpu, vcpu->arch.srr1); | |
36 | } | |
37 | ||
38 | int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | |
39 | unsigned int inst, int *advance) | |
40 | { | |
41 | int emulated = EMULATE_DONE; | |
42 | int rs; | |
43 | int rt; | |
44 | ||
45 | switch (get_op(inst)) { | |
46 | case 19: | |
47 | switch (get_xop(inst)) { | |
48 | case OP_19_XOP_RFI: | |
49 | kvmppc_emul_rfi(vcpu); | |
50 | kvmppc_set_exit_type(vcpu, EMULATED_RFI_EXITS); | |
51 | *advance = 0; | |
52 | break; | |
53 | ||
54 | default: | |
55 | emulated = EMULATE_FAIL; | |
56 | break; | |
57 | } | |
58 | break; | |
59 | ||
60 | case 31: | |
61 | switch (get_xop(inst)) { | |
62 | ||
63 | case OP_31_XOP_MFMSR: | |
64 | rt = get_rt(inst); | |
65 | vcpu->arch.gpr[rt] = vcpu->arch.msr; | |
66 | kvmppc_set_exit_type(vcpu, EMULATED_MFMSR_EXITS); | |
67 | break; | |
68 | ||
69 | case OP_31_XOP_MTMSR: | |
70 | rs = get_rs(inst); | |
71 | kvmppc_set_exit_type(vcpu, EMULATED_MTMSR_EXITS); | |
72 | kvmppc_set_msr(vcpu, vcpu->arch.gpr[rs]); | |
73 | break; | |
74 | ||
75 | case OP_31_XOP_WRTEE: | |
76 | rs = get_rs(inst); | |
77 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | |
78 | | (vcpu->arch.gpr[rs] & MSR_EE); | |
79 | kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS); | |
80 | break; | |
81 | ||
82 | case OP_31_XOP_WRTEEI: | |
83 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | |
84 | | (inst & MSR_EE); | |
85 | kvmppc_set_exit_type(vcpu, EMULATED_WRTEE_EXITS); | |
86 | break; | |
87 | ||
88 | default: | |
89 | emulated = EMULATE_FAIL; | |
90 | } | |
91 | ||
92 | break; | |
93 | ||
94 | default: | |
95 | emulated = EMULATE_FAIL; | |
96 | } | |
97 | ||
98 | return emulated; | |
99 | } | |
100 | ||
101 | int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | |
102 | { | |
103 | int emulated = EMULATE_DONE; | |
104 | ||
105 | switch (sprn) { | |
106 | case SPRN_DEAR: | |
107 | vcpu->arch.dear = vcpu->arch.gpr[rs]; break; | |
108 | case SPRN_ESR: | |
109 | vcpu->arch.esr = vcpu->arch.gpr[rs]; break; | |
110 | case SPRN_DBCR0: | |
111 | vcpu->arch.dbcr0 = vcpu->arch.gpr[rs]; break; | |
112 | case SPRN_DBCR1: | |
113 | vcpu->arch.dbcr1 = vcpu->arch.gpr[rs]; break; | |
114 | case SPRN_TSR: | |
115 | vcpu->arch.tsr &= ~vcpu->arch.gpr[rs]; break; | |
116 | case SPRN_TCR: | |
117 | vcpu->arch.tcr = vcpu->arch.gpr[rs]; | |
118 | kvmppc_emulate_dec(vcpu); | |
119 | break; | |
120 | ||
121 | /* Note: SPRG4-7 are user-readable. These values are | |
122 | * loaded into the real SPRGs when resuming the | |
123 | * guest. */ | |
124 | case SPRN_SPRG4: | |
125 | vcpu->arch.sprg4 = vcpu->arch.gpr[rs]; break; | |
126 | case SPRN_SPRG5: | |
127 | vcpu->arch.sprg5 = vcpu->arch.gpr[rs]; break; | |
128 | case SPRN_SPRG6: | |
129 | vcpu->arch.sprg6 = vcpu->arch.gpr[rs]; break; | |
130 | case SPRN_SPRG7: | |
131 | vcpu->arch.sprg7 = vcpu->arch.gpr[rs]; break; | |
132 | ||
133 | case SPRN_IVPR: | |
134 | vcpu->arch.ivpr = vcpu->arch.gpr[rs]; | |
135 | break; | |
136 | case SPRN_IVOR0: | |
137 | vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] = vcpu->arch.gpr[rs]; | |
138 | break; | |
139 | case SPRN_IVOR1: | |
140 | vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK] = vcpu->arch.gpr[rs]; | |
141 | break; | |
142 | case SPRN_IVOR2: | |
143 | vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE] = vcpu->arch.gpr[rs]; | |
144 | break; | |
145 | case SPRN_IVOR3: | |
146 | vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE] = vcpu->arch.gpr[rs]; | |
147 | break; | |
148 | case SPRN_IVOR4: | |
149 | vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL] = vcpu->arch.gpr[rs]; | |
150 | break; | |
151 | case SPRN_IVOR5: | |
152 | vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT] = vcpu->arch.gpr[rs]; | |
153 | break; | |
154 | case SPRN_IVOR6: | |
155 | vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM] = vcpu->arch.gpr[rs]; | |
156 | break; | |
157 | case SPRN_IVOR7: | |
158 | vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL] = vcpu->arch.gpr[rs]; | |
159 | break; | |
160 | case SPRN_IVOR8: | |
161 | vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL] = vcpu->arch.gpr[rs]; | |
162 | break; | |
163 | case SPRN_IVOR9: | |
164 | vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL] = vcpu->arch.gpr[rs]; | |
165 | break; | |
166 | case SPRN_IVOR10: | |
167 | vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER] = vcpu->arch.gpr[rs]; | |
168 | break; | |
169 | case SPRN_IVOR11: | |
170 | vcpu->arch.ivor[BOOKE_IRQPRIO_FIT] = vcpu->arch.gpr[rs]; | |
171 | break; | |
172 | case SPRN_IVOR12: | |
173 | vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG] = vcpu->arch.gpr[rs]; | |
174 | break; | |
175 | case SPRN_IVOR13: | |
176 | vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS] = vcpu->arch.gpr[rs]; | |
177 | break; | |
178 | case SPRN_IVOR14: | |
179 | vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS] = vcpu->arch.gpr[rs]; | |
180 | break; | |
181 | case SPRN_IVOR15: | |
182 | vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG] = vcpu->arch.gpr[rs]; | |
183 | break; | |
184 | ||
185 | default: | |
186 | emulated = EMULATE_FAIL; | |
187 | } | |
188 | ||
189 | return emulated; | |
190 | } | |
191 | ||
192 | int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | |
193 | { | |
194 | int emulated = EMULATE_DONE; | |
195 | ||
196 | switch (sprn) { | |
197 | case SPRN_IVPR: | |
198 | vcpu->arch.gpr[rt] = vcpu->arch.ivpr; break; | |
199 | case SPRN_DEAR: | |
200 | vcpu->arch.gpr[rt] = vcpu->arch.dear; break; | |
201 | case SPRN_ESR: | |
202 | vcpu->arch.gpr[rt] = vcpu->arch.esr; break; | |
203 | case SPRN_DBCR0: | |
204 | vcpu->arch.gpr[rt] = vcpu->arch.dbcr0; break; | |
205 | case SPRN_DBCR1: | |
206 | vcpu->arch.gpr[rt] = vcpu->arch.dbcr1; break; | |
207 | ||
208 | case SPRN_IVOR0: | |
209 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]; | |
210 | break; | |
211 | case SPRN_IVOR1: | |
212 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK]; | |
213 | break; | |
214 | case SPRN_IVOR2: | |
215 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE]; | |
216 | break; | |
217 | case SPRN_IVOR3: | |
218 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE]; | |
219 | break; | |
220 | case SPRN_IVOR4: | |
221 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL]; | |
222 | break; | |
223 | case SPRN_IVOR5: | |
224 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT]; | |
225 | break; | |
226 | case SPRN_IVOR6: | |
227 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM]; | |
228 | break; | |
229 | case SPRN_IVOR7: | |
230 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL]; | |
231 | break; | |
232 | case SPRN_IVOR8: | |
233 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL]; | |
234 | break; | |
235 | case SPRN_IVOR9: | |
236 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL]; | |
237 | break; | |
238 | case SPRN_IVOR10: | |
239 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER]; | |
240 | break; | |
241 | case SPRN_IVOR11: | |
242 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_FIT]; | |
243 | break; | |
244 | case SPRN_IVOR12: | |
245 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG]; | |
246 | break; | |
247 | case SPRN_IVOR13: | |
248 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS]; | |
249 | break; | |
250 | case SPRN_IVOR14: | |
251 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS]; | |
252 | break; | |
253 | case SPRN_IVOR15: | |
254 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG]; | |
255 | break; | |
256 | ||
257 | default: | |
258 | emulated = EMULATE_FAIL; | |
259 | } | |
260 | ||
261 | return emulated; | |
262 | } |