diff options
-rw-r--r-- | arch/mips/kvm/emulate.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index fbf169fb63df..07f554c72cb8 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c | |||
@@ -912,7 +912,13 @@ unsigned int kvm_mips_config1_wrmask(struct kvm_vcpu *vcpu) | |||
912 | unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu) | 912 | unsigned int kvm_mips_config3_wrmask(struct kvm_vcpu *vcpu) |
913 | { | 913 | { |
914 | /* Config4 is optional */ | 914 | /* Config4 is optional */ |
915 | return MIPS_CONF_M; | 915 | unsigned int mask = MIPS_CONF_M; |
916 | |||
917 | /* Permit MSA to be present if MSA is supported */ | ||
918 | if (kvm_mips_guest_can_have_msa(&vcpu->arch)) | ||
919 | mask |= MIPS_CONF3_MSA; | ||
920 | |||
921 | return mask; | ||
916 | } | 922 | } |
917 | 923 | ||
918 | /** | 924 | /** |
@@ -939,6 +945,10 @@ unsigned int kvm_mips_config5_wrmask(struct kvm_vcpu *vcpu) | |||
939 | { | 945 | { |
940 | unsigned int mask = 0; | 946 | unsigned int mask = 0; |
941 | 947 | ||
948 | /* Permit MSAEn changes if MSA supported and enabled */ | ||
949 | if (kvm_mips_guest_has_msa(&vcpu->arch)) | ||
950 | mask |= MIPS_CONF5_MSAEN; | ||
951 | |||
942 | /* | 952 | /* |
943 | * Permit guest FPU mode changes if FPU is enabled and the relevant | 953 | * Permit guest FPU mode changes if FPU is enabled and the relevant |
944 | * feature exists according to FIR register. | 954 | * feature exists according to FIR register. |
@@ -1126,6 +1136,18 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, | |||
1126 | kvm_drop_fpu(vcpu); | 1136 | kvm_drop_fpu(vcpu); |
1127 | 1137 | ||
1128 | /* | 1138 | /* |
1139 | * If MSA state is already live, it is undefined | ||
1140 | * how it interacts with FR=0 FPU state, and we | ||
1141 | * don't want to hit reserved instruction | ||
1142 | * exceptions trying to save the MSA state later | ||
1143 | * when CU=1 && FR=1, so play it safe and save | ||
1144 | * it first. | ||
1145 | */ | ||
1146 | if (change & ST0_CU1 && !(val & ST0_FR) && | ||
1147 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) | ||
1148 | kvm_lose_fpu(vcpu); | ||
1149 | |||
1150 | /* | ||
1129 | * Propagate CU1 (FPU enable) changes | 1151 | * Propagate CU1 (FPU enable) changes |
1130 | * immediately if the FPU context is already | 1152 | * immediately if the FPU context is already |
1131 | * loaded. When disabling we leave the context | 1153 | * loaded. When disabling we leave the context |
@@ -1160,7 +1182,7 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, | |||
1160 | val = old_val ^ change; | 1182 | val = old_val ^ change; |
1161 | 1183 | ||
1162 | 1184 | ||
1163 | /* Handle changes in FPU modes */ | 1185 | /* Handle changes in FPU/MSA modes */ |
1164 | preempt_disable(); | 1186 | preempt_disable(); |
1165 | 1187 | ||
1166 | /* | 1188 | /* |
@@ -1171,6 +1193,17 @@ enum emulation_result kvm_mips_emulate_CP0(uint32_t inst, uint32_t *opc, | |||
1171 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) | 1193 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_FPU) |
1172 | change_c0_config5(MIPS_CONF5_FRE, val); | 1194 | change_c0_config5(MIPS_CONF5_FRE, val); |
1173 | 1195 | ||
1196 | /* | ||
1197 | * Propagate MSAEn changes immediately if the | ||
1198 | * MSA context is already loaded. When disabling | ||
1199 | * we leave the context loaded so it can be | ||
1200 | * quickly enabled again in the near future. | ||
1201 | */ | ||
1202 | if (change & MIPS_CONF5_MSAEN && | ||
1203 | vcpu->arch.fpu_inuse & KVM_MIPS_FPU_MSA) | ||
1204 | change_c0_config5(MIPS_CONF5_MSAEN, | ||
1205 | val); | ||
1206 | |||
1174 | preempt_enable(); | 1207 | preempt_enable(); |
1175 | 1208 | ||
1176 | kvm_write_c0_guest_config5(cop0, val); | 1209 | kvm_write_c0_guest_config5(cop0, val); |