diff options
-rw-r--r-- | arch/powerpc/kvm/booke.c | 74 | ||||
-rw-r--r-- | arch/powerpc/kvm/booke.h | 6 | ||||
-rw-r--r-- | arch/powerpc/kvm/bookehv_interrupts.S | 9 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_emulate.c | 20 |
4 files changed, 101 insertions, 8 deletions
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 91e7217db9d9..8ace6120ef9b 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c | |||
@@ -168,6 +168,40 @@ static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu) | |||
168 | #endif | 168 | #endif |
169 | } | 169 | } |
170 | 170 | ||
171 | /* | ||
172 | * Simulate AltiVec unavailable fault to load guest state | ||
173 | * from thread to AltiVec unit. | ||
174 | * It requires to be called with preemption disabled. | ||
175 | */ | ||
176 | static inline void kvmppc_load_guest_altivec(struct kvm_vcpu *vcpu) | ||
177 | { | ||
178 | #ifdef CONFIG_ALTIVEC | ||
179 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) { | ||
180 | if (!(current->thread.regs->msr & MSR_VEC)) { | ||
181 | enable_kernel_altivec(); | ||
182 | load_vr_state(&vcpu->arch.vr); | ||
183 | current->thread.vr_save_area = &vcpu->arch.vr; | ||
184 | current->thread.regs->msr |= MSR_VEC; | ||
185 | } | ||
186 | } | ||
187 | #endif | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Save guest vcpu AltiVec state into thread. | ||
192 | * It requires to be called with preemption disabled. | ||
193 | */ | ||
194 | static inline void kvmppc_save_guest_altivec(struct kvm_vcpu *vcpu) | ||
195 | { | ||
196 | #ifdef CONFIG_ALTIVEC | ||
197 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) { | ||
198 | if (current->thread.regs->msr & MSR_VEC) | ||
199 | giveup_altivec(current); | ||
200 | current->thread.vr_save_area = NULL; | ||
201 | } | ||
202 | #endif | ||
203 | } | ||
204 | |||
171 | static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) | 205 | static void kvmppc_vcpu_sync_debug(struct kvm_vcpu *vcpu) |
172 | { | 206 | { |
173 | /* Synchronize guest's desire to get debug interrupts into shadow MSR */ | 207 | /* Synchronize guest's desire to get debug interrupts into shadow MSR */ |
@@ -375,9 +409,15 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | |||
375 | case BOOKE_IRQPRIO_ITLB_MISS: | 409 | case BOOKE_IRQPRIO_ITLB_MISS: |
376 | case BOOKE_IRQPRIO_SYSCALL: | 410 | case BOOKE_IRQPRIO_SYSCALL: |
377 | case BOOKE_IRQPRIO_FP_UNAVAIL: | 411 | case BOOKE_IRQPRIO_FP_UNAVAIL: |
412 | #ifdef CONFIG_SPE_POSSIBLE | ||
378 | case BOOKE_IRQPRIO_SPE_UNAVAIL: | 413 | case BOOKE_IRQPRIO_SPE_UNAVAIL: |
379 | case BOOKE_IRQPRIO_SPE_FP_DATA: | 414 | case BOOKE_IRQPRIO_SPE_FP_DATA: |
380 | case BOOKE_IRQPRIO_SPE_FP_ROUND: | 415 | case BOOKE_IRQPRIO_SPE_FP_ROUND: |
416 | #endif | ||
417 | #ifdef CONFIG_ALTIVEC | ||
418 | case BOOKE_IRQPRIO_ALTIVEC_UNAVAIL: | ||
419 | case BOOKE_IRQPRIO_ALTIVEC_ASSIST: | ||
420 | #endif | ||
381 | case BOOKE_IRQPRIO_AP_UNAVAIL: | 421 | case BOOKE_IRQPRIO_AP_UNAVAIL: |
382 | allowed = 1; | 422 | allowed = 1; |
383 | msr_mask = MSR_CE | MSR_ME | MSR_DE; | 423 | msr_mask = MSR_CE | MSR_ME | MSR_DE; |
@@ -697,6 +737,17 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
697 | kvmppc_load_guest_fp(vcpu); | 737 | kvmppc_load_guest_fp(vcpu); |
698 | #endif | 738 | #endif |
699 | 739 | ||
740 | #ifdef CONFIG_ALTIVEC | ||
741 | /* Save userspace AltiVec state in stack */ | ||
742 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | ||
743 | enable_kernel_altivec(); | ||
744 | /* | ||
745 | * Since we can't trap on MSR_VEC in GS-mode, we consider the guest | ||
746 | * as always using the AltiVec. | ||
747 | */ | ||
748 | kvmppc_load_guest_altivec(vcpu); | ||
749 | #endif | ||
750 | |||
700 | /* Switch to guest debug context */ | 751 | /* Switch to guest debug context */ |
701 | debug = vcpu->arch.dbg_reg; | 752 | debug = vcpu->arch.dbg_reg; |
702 | switch_booke_debug_regs(&debug); | 753 | switch_booke_debug_regs(&debug); |
@@ -719,6 +770,10 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | |||
719 | kvmppc_save_guest_fp(vcpu); | 770 | kvmppc_save_guest_fp(vcpu); |
720 | #endif | 771 | #endif |
721 | 772 | ||
773 | #ifdef CONFIG_ALTIVEC | ||
774 | kvmppc_save_guest_altivec(vcpu); | ||
775 | #endif | ||
776 | |||
722 | out: | 777 | out: |
723 | vcpu->mode = OUTSIDE_GUEST_MODE; | 778 | vcpu->mode = OUTSIDE_GUEST_MODE; |
724 | return ret; | 779 | return ret; |
@@ -1025,7 +1080,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
1025 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND); | 1080 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND); |
1026 | r = RESUME_GUEST; | 1081 | r = RESUME_GUEST; |
1027 | break; | 1082 | break; |
1028 | #else | 1083 | #elif defined(CONFIG_SPE_POSSIBLE) |
1029 | case BOOKE_INTERRUPT_SPE_UNAVAIL: | 1084 | case BOOKE_INTERRUPT_SPE_UNAVAIL: |
1030 | /* | 1085 | /* |
1031 | * Guest wants SPE, but host kernel doesn't support it. Send | 1086 | * Guest wants SPE, but host kernel doesn't support it. Send |
@@ -1046,6 +1101,22 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
1046 | run->hw.hardware_exit_reason = exit_nr; | 1101 | run->hw.hardware_exit_reason = exit_nr; |
1047 | r = RESUME_HOST; | 1102 | r = RESUME_HOST; |
1048 | break; | 1103 | break; |
1104 | #endif /* CONFIG_SPE_POSSIBLE */ | ||
1105 | |||
1106 | /* | ||
1107 | * On cores with Vector category, KVM is loaded only if CONFIG_ALTIVEC, | ||
1108 | * see kvmppc_core_check_processor_compat(). | ||
1109 | */ | ||
1110 | #ifdef CONFIG_ALTIVEC | ||
1111 | case BOOKE_INTERRUPT_ALTIVEC_UNAVAIL: | ||
1112 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_UNAVAIL); | ||
1113 | r = RESUME_GUEST; | ||
1114 | break; | ||
1115 | |||
1116 | case BOOKE_INTERRUPT_ALTIVEC_ASSIST: | ||
1117 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_ASSIST); | ||
1118 | r = RESUME_GUEST; | ||
1119 | break; | ||
1049 | #endif | 1120 | #endif |
1050 | 1121 | ||
1051 | case BOOKE_INTERRUPT_DATA_STORAGE: | 1122 | case BOOKE_INTERRUPT_DATA_STORAGE: |
@@ -1223,6 +1294,7 @@ out: | |||
1223 | /* interrupts now hard-disabled */ | 1294 | /* interrupts now hard-disabled */ |
1224 | kvmppc_fix_ee_before_entry(); | 1295 | kvmppc_fix_ee_before_entry(); |
1225 | kvmppc_load_guest_fp(vcpu); | 1296 | kvmppc_load_guest_fp(vcpu); |
1297 | kvmppc_load_guest_altivec(vcpu); | ||
1226 | } | 1298 | } |
1227 | } | 1299 | } |
1228 | 1300 | ||
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index e73d513f72d0..22ba08ea68e9 100644 --- a/arch/powerpc/kvm/booke.h +++ b/arch/powerpc/kvm/booke.h | |||
@@ -32,9 +32,15 @@ | |||
32 | #define BOOKE_IRQPRIO_ALIGNMENT 2 | 32 | #define BOOKE_IRQPRIO_ALIGNMENT 2 |
33 | #define BOOKE_IRQPRIO_PROGRAM 3 | 33 | #define BOOKE_IRQPRIO_PROGRAM 3 |
34 | #define BOOKE_IRQPRIO_FP_UNAVAIL 4 | 34 | #define BOOKE_IRQPRIO_FP_UNAVAIL 4 |
35 | #ifdef CONFIG_SPE_POSSIBLE | ||
35 | #define BOOKE_IRQPRIO_SPE_UNAVAIL 5 | 36 | #define BOOKE_IRQPRIO_SPE_UNAVAIL 5 |
36 | #define BOOKE_IRQPRIO_SPE_FP_DATA 6 | 37 | #define BOOKE_IRQPRIO_SPE_FP_DATA 6 |
37 | #define BOOKE_IRQPRIO_SPE_FP_ROUND 7 | 38 | #define BOOKE_IRQPRIO_SPE_FP_ROUND 7 |
39 | #endif | ||
40 | #ifdef CONFIG_PPC_E500MC | ||
41 | #define BOOKE_IRQPRIO_ALTIVEC_UNAVAIL 5 | ||
42 | #define BOOKE_IRQPRIO_ALTIVEC_ASSIST 6 | ||
43 | #endif | ||
38 | #define BOOKE_IRQPRIO_SYSCALL 8 | 44 | #define BOOKE_IRQPRIO_SYSCALL 8 |
39 | #define BOOKE_IRQPRIO_AP_UNAVAIL 9 | 45 | #define BOOKE_IRQPRIO_AP_UNAVAIL 9 |
40 | #define BOOKE_IRQPRIO_DTLB_MISS 10 | 46 | #define BOOKE_IRQPRIO_DTLB_MISS 10 |
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S index e9fa56a911fd..c8e4da55cb43 100644 --- a/arch/powerpc/kvm/bookehv_interrupts.S +++ b/arch/powerpc/kvm/bookehv_interrupts.S | |||
@@ -256,11 +256,9 @@ kvm_handler BOOKE_INTERRUPT_DTLB_MISS, EX_PARAMS_TLB, \ | |||
256 | SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) | 256 | SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) |
257 | kvm_handler BOOKE_INTERRUPT_ITLB_MISS, EX_PARAMS_TLB, \ | 257 | kvm_handler BOOKE_INTERRUPT_ITLB_MISS, EX_PARAMS_TLB, \ |
258 | SPRN_SRR0, SPRN_SRR1, 0 | 258 | SPRN_SRR0, SPRN_SRR1, 0 |
259 | kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, EX_PARAMS(GEN), \ | 259 | kvm_handler BOOKE_INTERRUPT_ALTIVEC_UNAVAIL, EX_PARAMS(GEN), \ |
260 | SPRN_SRR0, SPRN_SRR1, 0 | 260 | SPRN_SRR0, SPRN_SRR1, 0 |
261 | kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, EX_PARAMS(GEN), \ | 261 | kvm_handler BOOKE_INTERRUPT_ALTIVEC_ASSIST, EX_PARAMS(GEN), \ |
262 | SPRN_SRR0, SPRN_SRR1, 0 | ||
263 | kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, EX_PARAMS(GEN), \ | ||
264 | SPRN_SRR0, SPRN_SRR1, 0 | 262 | SPRN_SRR0, SPRN_SRR1, 0 |
265 | kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, EX_PARAMS(GEN), \ | 263 | kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, EX_PARAMS(GEN), \ |
266 | SPRN_SRR0, SPRN_SRR1, 0 | 264 | SPRN_SRR0, SPRN_SRR1, 0 |
@@ -361,9 +359,6 @@ kvm_lvl_handler BOOKE_INTERRUPT_WATCHDOG, \ | |||
361 | kvm_handler BOOKE_INTERRUPT_DTLB_MISS, \ | 359 | kvm_handler BOOKE_INTERRUPT_DTLB_MISS, \ |
362 | SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) | 360 | SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) |
363 | kvm_handler BOOKE_INTERRUPT_ITLB_MISS, SPRN_SRR0, SPRN_SRR1, 0 | 361 | kvm_handler BOOKE_INTERRUPT_ITLB_MISS, SPRN_SRR0, SPRN_SRR1, 0 |
364 | kvm_handler BOOKE_INTERRUPT_SPE_UNAVAIL, SPRN_SRR0, SPRN_SRR1, 0 | ||
365 | kvm_handler BOOKE_INTERRUPT_SPE_FP_DATA, SPRN_SRR0, SPRN_SRR1, 0 | ||
366 | kvm_handler BOOKE_INTERRUPT_SPE_FP_ROUND, SPRN_SRR0, SPRN_SRR1, 0 | ||
367 | kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, SPRN_SRR0, SPRN_SRR1, 0 | 362 | kvm_handler BOOKE_INTERRUPT_PERFORMANCE_MONITOR, SPRN_SRR0, SPRN_SRR1, 0 |
368 | kvm_handler BOOKE_INTERRUPT_DOORBELL, SPRN_SRR0, SPRN_SRR1, 0 | 363 | kvm_handler BOOKE_INTERRUPT_DOORBELL, SPRN_SRR0, SPRN_SRR1, 0 |
369 | kvm_lvl_handler BOOKE_INTERRUPT_DOORBELL_CRITICAL, \ | 364 | kvm_lvl_handler BOOKE_INTERRUPT_DOORBELL_CRITICAL, \ |
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c index c99c40e9182a..ce7291c79f6c 100644 --- a/arch/powerpc/kvm/e500_emulate.c +++ b/arch/powerpc/kvm/e500_emulate.c | |||
@@ -259,6 +259,7 @@ int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_va | |||
259 | break; | 259 | break; |
260 | 260 | ||
261 | /* extra exceptions */ | 261 | /* extra exceptions */ |
262 | #ifdef CONFIG_SPE_POSSIBLE | ||
262 | case SPRN_IVOR32: | 263 | case SPRN_IVOR32: |
263 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val; | 264 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val; |
264 | break; | 265 | break; |
@@ -268,6 +269,15 @@ int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_va | |||
268 | case SPRN_IVOR34: | 269 | case SPRN_IVOR34: |
269 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val; | 270 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val; |
270 | break; | 271 | break; |
272 | #endif | ||
273 | #ifdef CONFIG_ALTIVEC | ||
274 | case SPRN_IVOR32: | ||
275 | vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL] = spr_val; | ||
276 | break; | ||
277 | case SPRN_IVOR33: | ||
278 | vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST] = spr_val; | ||
279 | break; | ||
280 | #endif | ||
271 | case SPRN_IVOR35: | 281 | case SPRN_IVOR35: |
272 | vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val; | 282 | vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val; |
273 | break; | 283 | break; |
@@ -381,6 +391,7 @@ int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_v | |||
381 | break; | 391 | break; |
382 | 392 | ||
383 | /* extra exceptions */ | 393 | /* extra exceptions */ |
394 | #ifdef CONFIG_SPE_POSSIBLE | ||
384 | case SPRN_IVOR32: | 395 | case SPRN_IVOR32: |
385 | *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]; | 396 | *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]; |
386 | break; | 397 | break; |
@@ -390,6 +401,15 @@ int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_v | |||
390 | case SPRN_IVOR34: | 401 | case SPRN_IVOR34: |
391 | *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]; | 402 | *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]; |
392 | break; | 403 | break; |
404 | #endif | ||
405 | #ifdef CONFIG_ALTIVEC | ||
406 | case SPRN_IVOR32: | ||
407 | *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL]; | ||
408 | break; | ||
409 | case SPRN_IVOR33: | ||
410 | *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST]; | ||
411 | break; | ||
412 | #endif | ||
393 | case SPRN_IVOR35: | 413 | case SPRN_IVOR35: |
394 | *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; | 414 | *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; |
395 | break; | 415 | break; |