aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kvm/book3s_pr.c85
1 files changed, 34 insertions, 51 deletions
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index e40765f8cbad..e76aec38ec21 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -710,42 +710,6 @@ static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac)
710#endif 710#endif
711} 711}
712 712
713static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
714{
715 ulong srr0 = kvmppc_get_pc(vcpu);
716 u32 last_inst = kvmppc_get_last_inst(vcpu);
717 int ret;
718
719 ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
720 if (ret == -ENOENT) {
721 ulong msr = kvmppc_get_msr(vcpu);
722
723 msr = kvmppc_set_field(msr, 33, 33, 1);
724 msr = kvmppc_set_field(msr, 34, 36, 0);
725 msr = kvmppc_set_field(msr, 42, 47, 0);
726 kvmppc_set_msr_fast(vcpu, msr);
727 kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
728 return EMULATE_AGAIN;
729 }
730
731 return EMULATE_DONE;
732}
733
734static int kvmppc_check_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr)
735{
736
737 /* Need to do paired single emulation? */
738 if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE))
739 return EMULATE_DONE;
740
741 /* Read out the instruction */
742 if (kvmppc_read_inst(vcpu) == EMULATE_DONE)
743 /* Need to emulate */
744 return EMULATE_FAIL;
745
746 return EMULATE_AGAIN;
747}
748
749/* Handle external providers (FPU, Altivec, VSX) */ 713/* Handle external providers (FPU, Altivec, VSX) */
750static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, 714static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
751 ulong msr) 715 ulong msr)
@@ -1149,31 +1113,49 @@ program_interrupt:
1149 case BOOK3S_INTERRUPT_VSX: 1113 case BOOK3S_INTERRUPT_VSX:
1150 { 1114 {
1151 int ext_msr = 0; 1115 int ext_msr = 0;
1116 int emul;
1117 ulong pc;
1118 u32 last_inst;
1119
1120 if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE) {
1121 /* Do paired single instruction emulation */
1122 pc = kvmppc_get_pc(vcpu);
1123 last_inst = kvmppc_get_last_inst(vcpu);
1124 emul = kvmppc_ld(vcpu, &pc, sizeof(u32), &last_inst,
1125 false);
1126 if (emul == EMULATE_DONE)
1127 goto program_interrupt;
1128 else
1129 r = RESUME_GUEST;
1152 1130
1153 switch (exit_nr) { 1131 break;
1154 case BOOK3S_INTERRUPT_FP_UNAVAIL: ext_msr = MSR_FP; break;
1155 case BOOK3S_INTERRUPT_ALTIVEC: ext_msr = MSR_VEC; break;
1156 case BOOK3S_INTERRUPT_VSX: ext_msr = MSR_VSX; break;
1157 } 1132 }
1158 1133
1159 switch (kvmppc_check_ext(vcpu, exit_nr)) { 1134 /* Enable external provider */
1160 case EMULATE_DONE: 1135 switch (exit_nr) {
1161 /* everything ok - let's enable the ext */ 1136 case BOOK3S_INTERRUPT_FP_UNAVAIL:
1162 r = kvmppc_handle_ext(vcpu, exit_nr, ext_msr); 1137 ext_msr = MSR_FP;
1163 break; 1138 break;
1164 case EMULATE_FAIL: 1139
1165 /* we need to emulate this instruction */ 1140 case BOOK3S_INTERRUPT_ALTIVEC:
1166 goto program_interrupt; 1141 ext_msr = MSR_VEC;
1167 break; 1142 break;
1168 default: 1143
1169 /* nothing to worry about - go again */ 1144 case BOOK3S_INTERRUPT_VSX:
1145 ext_msr = MSR_VSX;
1170 break; 1146 break;
1171 } 1147 }
1148
1149 r = kvmppc_handle_ext(vcpu, exit_nr, ext_msr);
1172 break; 1150 break;
1173 } 1151 }
1174 case BOOK3S_INTERRUPT_ALIGNMENT: 1152 case BOOK3S_INTERRUPT_ALIGNMENT:
1175 if (kvmppc_read_inst(vcpu) == EMULATE_DONE) { 1153 {
1176 u32 last_inst = kvmppc_get_last_inst(vcpu); 1154 ulong pc = kvmppc_get_pc(vcpu);
1155 u32 last_inst = kvmppc_get_last_inst(vcpu);
1156 int emul = kvmppc_ld(vcpu, &pc, sizeof(u32), &last_inst, false);
1157
1158 if (emul == EMULATE_DONE) {
1177 u32 dsisr; 1159 u32 dsisr;
1178 u64 dar; 1160 u64 dar;
1179 1161
@@ -1187,6 +1169,7 @@ program_interrupt:
1187 } 1169 }
1188 r = RESUME_GUEST; 1170 r = RESUME_GUEST;
1189 break; 1171 break;
1172 }
1190#ifdef CONFIG_PPC_BOOK3S_64 1173#ifdef CONFIG_PPC_BOOK3S_64
1191 case BOOK3S_INTERRUPT_FAC_UNAVAIL: 1174 case BOOK3S_INTERRUPT_FAC_UNAVAIL:
1192 kvmppc_handle_fac(vcpu, vcpu->arch.shadow_fscr >> 56); 1175 kvmppc_handle_fac(vcpu, vcpu->arch.shadow_fscr >> 56);