]>
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); | |
8e5b26b5 | 65 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.msr); |
d0c7dc03 HB |
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); | |
8e5b26b5 | 72 | kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs)); |
d0c7dc03 HB |
73 | break; |
74 | ||
75 | case OP_31_XOP_WRTEE: | |
76 | rs = get_rs(inst); | |
77 | vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | |
8e5b26b5 | 78 | | (kvmppc_get_gpr(vcpu, rs) & MSR_EE); |
d0c7dc03 HB |
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; | |
8e5b26b5 | 104 | ulong spr_val = kvmppc_get_gpr(vcpu, rs); |
d0c7dc03 HB |
105 | |
106 | switch (sprn) { | |
107 | case SPRN_DEAR: | |
8e5b26b5 | 108 | vcpu->arch.dear = spr_val; break; |
d0c7dc03 | 109 | case SPRN_ESR: |
8e5b26b5 | 110 | vcpu->arch.esr = spr_val; break; |
d0c7dc03 | 111 | case SPRN_DBCR0: |
8e5b26b5 | 112 | vcpu->arch.dbcr0 = spr_val; break; |
d0c7dc03 | 113 | case SPRN_DBCR1: |
8e5b26b5 | 114 | vcpu->arch.dbcr1 = spr_val; break; |
f7b200af | 115 | case SPRN_DBSR: |
8e5b26b5 | 116 | vcpu->arch.dbsr &= ~spr_val; break; |
d0c7dc03 | 117 | case SPRN_TSR: |
8e5b26b5 | 118 | vcpu->arch.tsr &= ~spr_val; break; |
d0c7dc03 | 119 | case SPRN_TCR: |
8e5b26b5 | 120 | vcpu->arch.tcr = spr_val; |
d0c7dc03 HB |
121 | kvmppc_emulate_dec(vcpu); |
122 | break; | |
123 | ||
124 | /* Note: SPRG4-7 are user-readable. These values are | |
125 | * loaded into the real SPRGs when resuming the | |
126 | * guest. */ | |
127 | case SPRN_SPRG4: | |
8e5b26b5 | 128 | vcpu->arch.sprg4 = spr_val; break; |
d0c7dc03 | 129 | case SPRN_SPRG5: |
8e5b26b5 | 130 | vcpu->arch.sprg5 = spr_val; break; |
d0c7dc03 | 131 | case SPRN_SPRG6: |
8e5b26b5 | 132 | vcpu->arch.sprg6 = spr_val; break; |
d0c7dc03 | 133 | case SPRN_SPRG7: |
8e5b26b5 | 134 | vcpu->arch.sprg7 = spr_val; break; |
d0c7dc03 HB |
135 | |
136 | case SPRN_IVPR: | |
8e5b26b5 | 137 | vcpu->arch.ivpr = spr_val; |
d0c7dc03 HB |
138 | break; |
139 | case SPRN_IVOR0: | |
8e5b26b5 | 140 | vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] = spr_val; |
d0c7dc03 HB |
141 | break; |
142 | case SPRN_IVOR1: | |
8e5b26b5 | 143 | vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK] = spr_val; |
d0c7dc03 HB |
144 | break; |
145 | case SPRN_IVOR2: | |
8e5b26b5 | 146 | vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE] = spr_val; |
d0c7dc03 HB |
147 | break; |
148 | case SPRN_IVOR3: | |
8e5b26b5 | 149 | vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE] = spr_val; |
d0c7dc03 HB |
150 | break; |
151 | case SPRN_IVOR4: | |
8e5b26b5 | 152 | vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL] = spr_val; |
d0c7dc03 HB |
153 | break; |
154 | case SPRN_IVOR5: | |
8e5b26b5 | 155 | vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT] = spr_val; |
d0c7dc03 HB |
156 | break; |
157 | case SPRN_IVOR6: | |
8e5b26b5 | 158 | vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM] = spr_val; |
d0c7dc03 HB |
159 | break; |
160 | case SPRN_IVOR7: | |
8e5b26b5 | 161 | vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL] = spr_val; |
d0c7dc03 HB |
162 | break; |
163 | case SPRN_IVOR8: | |
8e5b26b5 | 164 | vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL] = spr_val; |
d0c7dc03 HB |
165 | break; |
166 | case SPRN_IVOR9: | |
8e5b26b5 | 167 | vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL] = spr_val; |
d0c7dc03 HB |
168 | break; |
169 | case SPRN_IVOR10: | |
8e5b26b5 | 170 | vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER] = spr_val; |
d0c7dc03 HB |
171 | break; |
172 | case SPRN_IVOR11: | |
8e5b26b5 | 173 | vcpu->arch.ivor[BOOKE_IRQPRIO_FIT] = spr_val; |
d0c7dc03 HB |
174 | break; |
175 | case SPRN_IVOR12: | |
8e5b26b5 | 176 | vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG] = spr_val; |
d0c7dc03 HB |
177 | break; |
178 | case SPRN_IVOR13: | |
8e5b26b5 | 179 | vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS] = spr_val; |
d0c7dc03 HB |
180 | break; |
181 | case SPRN_IVOR14: | |
8e5b26b5 | 182 | vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS] = spr_val; |
d0c7dc03 HB |
183 | break; |
184 | case SPRN_IVOR15: | |
8e5b26b5 | 185 | vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG] = spr_val; |
d0c7dc03 HB |
186 | break; |
187 | ||
188 | default: | |
189 | emulated = EMULATE_FAIL; | |
190 | } | |
191 | ||
192 | return emulated; | |
193 | } | |
194 | ||
195 | int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | |
196 | { | |
197 | int emulated = EMULATE_DONE; | |
198 | ||
199 | switch (sprn) { | |
200 | case SPRN_IVPR: | |
8e5b26b5 | 201 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivpr); break; |
d0c7dc03 | 202 | case SPRN_DEAR: |
8e5b26b5 | 203 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.dear); break; |
d0c7dc03 | 204 | case SPRN_ESR: |
8e5b26b5 | 205 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.esr); break; |
d0c7dc03 | 206 | case SPRN_DBCR0: |
8e5b26b5 | 207 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbcr0); break; |
d0c7dc03 | 208 | case SPRN_DBCR1: |
8e5b26b5 | 209 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbcr1); break; |
f7b200af | 210 | case SPRN_DBSR: |
8e5b26b5 | 211 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbsr); break; |
d0c7dc03 HB |
212 | |
213 | case SPRN_IVOR0: | |
8e5b26b5 | 214 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]); |
d0c7dc03 HB |
215 | break; |
216 | case SPRN_IVOR1: | |
8e5b26b5 | 217 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK]); |
d0c7dc03 HB |
218 | break; |
219 | case SPRN_IVOR2: | |
8e5b26b5 | 220 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE]); |
d0c7dc03 HB |
221 | break; |
222 | case SPRN_IVOR3: | |
8e5b26b5 | 223 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE]); |
d0c7dc03 HB |
224 | break; |
225 | case SPRN_IVOR4: | |
8e5b26b5 | 226 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL]); |
d0c7dc03 HB |
227 | break; |
228 | case SPRN_IVOR5: | |
8e5b26b5 | 229 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT]); |
d0c7dc03 HB |
230 | break; |
231 | case SPRN_IVOR6: | |
8e5b26b5 | 232 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM]); |
d0c7dc03 HB |
233 | break; |
234 | case SPRN_IVOR7: | |
8e5b26b5 | 235 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL]); |
d0c7dc03 HB |
236 | break; |
237 | case SPRN_IVOR8: | |
8e5b26b5 | 238 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL]); |
d0c7dc03 HB |
239 | break; |
240 | case SPRN_IVOR9: | |
8e5b26b5 | 241 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL]); |
d0c7dc03 HB |
242 | break; |
243 | case SPRN_IVOR10: | |
8e5b26b5 | 244 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER]); |
d0c7dc03 HB |
245 | break; |
246 | case SPRN_IVOR11: | |
8e5b26b5 | 247 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_FIT]); |
d0c7dc03 HB |
248 | break; |
249 | case SPRN_IVOR12: | |
8e5b26b5 | 250 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG]); |
d0c7dc03 HB |
251 | break; |
252 | case SPRN_IVOR13: | |
8e5b26b5 | 253 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS]); |
d0c7dc03 HB |
254 | break; |
255 | case SPRN_IVOR14: | |
8e5b26b5 | 256 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS]); |
d0c7dc03 HB |
257 | break; |
258 | case SPRN_IVOR15: | |
8e5b26b5 | 259 | kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG]); |
d0c7dc03 HB |
260 | break; |
261 | ||
262 | default: | |
263 | emulated = EMULATE_FAIL; | |
264 | } | |
265 | ||
266 | return emulated; | |
267 | } |