diff options
Diffstat (limited to 'arch/powerpc/kvm/emulate.c')
| -rw-r--r-- | arch/powerpc/kvm/emulate.c | 221 |
1 files changed, 121 insertions, 100 deletions
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index ee04abaefe23..b0855e5d8905 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c | |||
| @@ -131,6 +131,125 @@ u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb) | |||
| 131 | return vcpu->arch.dec - jd; | 131 | return vcpu->arch.dec - jd; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||
| 135 | { | ||
| 136 | enum emulation_result emulated = EMULATE_DONE; | ||
| 137 | ulong spr_val = kvmppc_get_gpr(vcpu, rs); | ||
| 138 | |||
| 139 | switch (sprn) { | ||
| 140 | case SPRN_SRR0: | ||
| 141 | vcpu->arch.shared->srr0 = spr_val; | ||
| 142 | break; | ||
| 143 | case SPRN_SRR1: | ||
| 144 | vcpu->arch.shared->srr1 = spr_val; | ||
| 145 | break; | ||
| 146 | |||
| 147 | /* XXX We need to context-switch the timebase for | ||
| 148 | * watchdog and FIT. */ | ||
| 149 | case SPRN_TBWL: break; | ||
| 150 | case SPRN_TBWU: break; | ||
| 151 | |||
| 152 | case SPRN_MSSSR0: break; | ||
| 153 | |||
| 154 | case SPRN_DEC: | ||
| 155 | vcpu->arch.dec = spr_val; | ||
| 156 | kvmppc_emulate_dec(vcpu); | ||
| 157 | break; | ||
| 158 | |||
| 159 | case SPRN_SPRG0: | ||
| 160 | vcpu->arch.shared->sprg0 = spr_val; | ||
| 161 | break; | ||
| 162 | case SPRN_SPRG1: | ||
| 163 | vcpu->arch.shared->sprg1 = spr_val; | ||
| 164 | break; | ||
| 165 | case SPRN_SPRG2: | ||
| 166 | vcpu->arch.shared->sprg2 = spr_val; | ||
| 167 | break; | ||
| 168 | case SPRN_SPRG3: | ||
| 169 | vcpu->arch.shared->sprg3 = spr_val; | ||
| 170 | break; | ||
| 171 | |||
| 172 | default: | ||
| 173 | emulated = kvmppc_core_emulate_mtspr(vcpu, sprn, | ||
| 174 | spr_val); | ||
| 175 | if (emulated == EMULATE_FAIL) | ||
| 176 | printk(KERN_INFO "mtspr: unknown spr " | ||
| 177 | "0x%x\n", sprn); | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | |||
| 181 | kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS); | ||
| 182 | |||
| 183 | return emulated; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | ||
| 187 | { | ||
| 188 | enum emulation_result emulated = EMULATE_DONE; | ||
| 189 | ulong spr_val = 0; | ||
| 190 | |||
| 191 | switch (sprn) { | ||
| 192 | case SPRN_SRR0: | ||
| 193 | spr_val = vcpu->arch.shared->srr0; | ||
| 194 | break; | ||
| 195 | case SPRN_SRR1: | ||
| 196 | spr_val = vcpu->arch.shared->srr1; | ||
| 197 | break; | ||
| 198 | case SPRN_PVR: | ||
| 199 | spr_val = vcpu->arch.pvr; | ||
| 200 | break; | ||
| 201 | case SPRN_PIR: | ||
| 202 | spr_val = vcpu->vcpu_id; | ||
| 203 | break; | ||
| 204 | case SPRN_MSSSR0: | ||
| 205 | spr_val = 0; | ||
| 206 | break; | ||
| 207 | |||
| 208 | /* Note: mftb and TBRL/TBWL are user-accessible, so | ||
| 209 | * the guest can always access the real TB anyways. | ||
| 210 | * In fact, we probably will never see these traps. */ | ||
| 211 | case SPRN_TBWL: | ||
| 212 | spr_val = get_tb() >> 32; | ||
| 213 | break; | ||
| 214 | case SPRN_TBWU: | ||
| 215 | spr_val = get_tb(); | ||
| 216 | break; | ||
| 217 | |||
| 218 | case SPRN_SPRG0: | ||
| 219 | spr_val = vcpu->arch.shared->sprg0; | ||
| 220 | break; | ||
| 221 | case SPRN_SPRG1: | ||
| 222 | spr_val = vcpu->arch.shared->sprg1; | ||
| 223 | break; | ||
| 224 | case SPRN_SPRG2: | ||
| 225 | spr_val = vcpu->arch.shared->sprg2; | ||
| 226 | break; | ||
| 227 | case SPRN_SPRG3: | ||
| 228 | spr_val = vcpu->arch.shared->sprg3; | ||
| 229 | break; | ||
| 230 | /* Note: SPRG4-7 are user-readable, so we don't get | ||
| 231 | * a trap. */ | ||
| 232 | |||
| 233 | case SPRN_DEC: | ||
| 234 | spr_val = kvmppc_get_dec(vcpu, get_tb()); | ||
| 235 | break; | ||
| 236 | default: | ||
| 237 | emulated = kvmppc_core_emulate_mfspr(vcpu, sprn, | ||
| 238 | &spr_val); | ||
| 239 | if (unlikely(emulated == EMULATE_FAIL)) { | ||
| 240 | printk(KERN_INFO "mfspr: unknown spr " | ||
| 241 | "0x%x\n", sprn); | ||
| 242 | } | ||
| 243 | break; | ||
| 244 | } | ||
| 245 | |||
| 246 | if (emulated == EMULATE_DONE) | ||
| 247 | kvmppc_set_gpr(vcpu, rt, spr_val); | ||
| 248 | kvmppc_set_exit_type(vcpu, EMULATED_MFSPR_EXITS); | ||
| 249 | |||
| 250 | return emulated; | ||
| 251 | } | ||
| 252 | |||
| 134 | /* XXX to do: | 253 | /* XXX to do: |
| 135 | * lhax | 254 | * lhax |
| 136 | * lhaux | 255 | * lhaux |
| @@ -156,7 +275,6 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
| 156 | int sprn = get_sprn(inst); | 275 | int sprn = get_sprn(inst); |
| 157 | enum emulation_result emulated = EMULATE_DONE; | 276 | enum emulation_result emulated = EMULATE_DONE; |
| 158 | int advance = 1; | 277 | int advance = 1; |
| 159 | ulong spr_val = 0; | ||
| 160 | 278 | ||
| 161 | /* this default type might be overwritten by subcategories */ | 279 | /* this default type might be overwritten by subcategories */ |
| 162 | kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); | 280 | kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); |
| @@ -236,62 +354,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
| 236 | break; | 354 | break; |
| 237 | 355 | ||
| 238 | case OP_31_XOP_MFSPR: | 356 | case OP_31_XOP_MFSPR: |
| 239 | switch (sprn) { | 357 | emulated = kvmppc_emulate_mfspr(vcpu, sprn, rt); |
| 240 | case SPRN_SRR0: | ||
| 241 | spr_val = vcpu->arch.shared->srr0; | ||
| 242 | break; | ||
| 243 | case SPRN_SRR1: | ||
| 244 | spr_val = vcpu->arch.shared->srr1; | ||
| 245 | break; | ||
| 246 | case SPRN_PVR: | ||
| 247 | spr_val = vcpu->arch.pvr; | ||
| 248 | break; | ||
| 249 | case SPRN_PIR: | ||
| 250 | spr_val = vcpu->vcpu_id; | ||
| 251 | break; | ||
| 252 | case SPRN_MSSSR0: | ||
| 253 | spr_val = 0; | ||
| 254 | break; | ||
| 255 | |||
| 256 | /* Note: mftb and TBRL/TBWL are user-accessible, so | ||
| 257 | * the guest can always access the real TB anyways. | ||
| 258 | * In fact, we probably will never see these traps. */ | ||
| 259 | case SPRN_TBWL: | ||
| 260 | spr_val = get_tb() >> 32; | ||
| 261 | break; | ||
| 262 | case SPRN_TBWU: | ||
| 263 | spr_val = get_tb(); | ||
| 264 | break; | ||
| 265 | |||
| 266 | case SPRN_SPRG0: | ||
| 267 | spr_val = vcpu->arch.shared->sprg0; | ||
| 268 | break; | ||
| 269 | case SPRN_SPRG1: | ||
| 270 | spr_val = vcpu->arch.shared->sprg1; | ||
| 271 | break; | ||
| 272 | case SPRN_SPRG2: | ||
| 273 | spr_val = vcpu->arch.shared->sprg2; | ||
| 274 | break; | ||
| 275 | case SPRN_SPRG3: | ||
| 276 | spr_val = vcpu->arch.shared->sprg3; | ||
| 277 | break; | ||
| 278 | /* Note: SPRG4-7 are user-readable, so we don't get | ||
| 279 | * a trap. */ | ||
| 280 | |||
| 281 | case SPRN_DEC: | ||
| 282 | spr_val = kvmppc_get_dec(vcpu, get_tb()); | ||
| 283 | break; | ||
| 284 | default: | ||
| 285 | emulated = kvmppc_core_emulate_mfspr(vcpu, sprn, | ||
| 286 | &spr_val); | ||
| 287 | if (unlikely(emulated == EMULATE_FAIL)) { | ||
| 288 | printk(KERN_INFO "mfspr: unknown spr " | ||
| 289 | "0x%x\n", sprn); | ||
| 290 | } | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | kvmppc_set_gpr(vcpu, rt, spr_val); | ||
| 294 | kvmppc_set_exit_type(vcpu, EMULATED_MFSPR_EXITS); | ||
| 295 | break; | 358 | break; |
| 296 | 359 | ||
| 297 | case OP_31_XOP_STHX: | 360 | case OP_31_XOP_STHX: |
| @@ -308,49 +371,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
| 308 | break; | 371 | break; |
| 309 | 372 | ||
| 310 | case OP_31_XOP_MTSPR: | 373 | case OP_31_XOP_MTSPR: |
| 311 | spr_val = kvmppc_get_gpr(vcpu, rs); | 374 | emulated = kvmppc_emulate_mtspr(vcpu, sprn, rs); |
| 312 | switch (sprn) { | ||
| 313 | case SPRN_SRR0: | ||
| 314 | vcpu->arch.shared->srr0 = spr_val; | ||
| 315 | break; | ||
| 316 | case SPRN_SRR1: | ||
| 317 | vcpu->arch.shared->srr1 = spr_val; | ||
| 318 | break; | ||
| 319 | |||
| 320 | /* XXX We need to context-switch the timebase for | ||
| 321 | * watchdog and FIT. */ | ||
| 322 | case SPRN_TBWL: break; | ||
| 323 | case SPRN_TBWU: break; | ||
| 324 | |||
| 325 | case SPRN_MSSSR0: break; | ||
| 326 | |||
| 327 | case SPRN_DEC: | ||
| 328 | vcpu->arch.dec = spr_val; | ||
| 329 | kvmppc_emulate_dec(vcpu); | ||
| 330 | break; | ||
| 331 | |||
| 332 | case SPRN_SPRG0: | ||
| 333 | vcpu->arch.shared->sprg0 = spr_val; | ||
| 334 | break; | ||
| 335 | case SPRN_SPRG1: | ||
| 336 | vcpu->arch.shared->sprg1 = spr_val; | ||
| 337 | break; | ||
| 338 | case SPRN_SPRG2: | ||
| 339 | vcpu->arch.shared->sprg2 = spr_val; | ||
| 340 | break; | ||
| 341 | case SPRN_SPRG3: | ||
| 342 | vcpu->arch.shared->sprg3 = spr_val; | ||
| 343 | break; | ||
| 344 | |||
| 345 | default: | ||
| 346 | emulated = kvmppc_core_emulate_mtspr(vcpu, sprn, | ||
| 347 | spr_val); | ||
| 348 | if (emulated == EMULATE_FAIL) | ||
| 349 | printk(KERN_INFO "mtspr: unknown spr " | ||
| 350 | "0x%x\n", sprn); | ||
| 351 | break; | ||
| 352 | } | ||
| 353 | kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS); | ||
| 354 | break; | 375 | break; |
| 355 | 376 | ||
| 356 | case OP_31_XOP_DCBI: | 377 | case OP_31_XOP_DCBI: |
