Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: MIPS: Add CPUCFG emulation for Loongson-3

Loongson-3 overrides lwc2 instructions to implement CPUCFG and CSR
read/write functions. These instructions all cause guest exit so CSR
doesn't benifit KVM guest (and there are always legacy methods to
provide the same functions as CSR). So, we only emulate CPUCFG and let
it return a reduced feature list (which means the virtual CPU doesn't
have any other advanced features, including CSR) in KVM.

Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Message-Id: <1590220602-3547-12-git-send-email-chenhc@lemote.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Huacai Chen and committed by
Paolo Bonzini
7f2a83f1 f21db309

+92
+3
arch/mips/include/asm/kvm_host.h
··· 173 173 u64 vz_ghfc_exits; 174 174 u64 vz_gpa_exits; 175 175 u64 vz_resvd_exits; 176 + #ifdef CONFIG_CPU_LOONGSON64 177 + u64 vz_cpucfg_exits; 178 + #endif 176 179 #endif 177 180 u64 halt_successful_poll; 178 181 u64 halt_attempted_poll;
+11
arch/mips/include/uapi/asm/inst.h
··· 1012 1012 ;)))))) 1013 1013 }; 1014 1014 1015 + struct loongson3_lscsr_format { /* Loongson-3 CPUCFG&CSR read/write format */ 1016 + __BITFIELD_FIELD(unsigned int opcode : 6, 1017 + __BITFIELD_FIELD(unsigned int rs : 5, 1018 + __BITFIELD_FIELD(unsigned int fr : 5, 1019 + __BITFIELD_FIELD(unsigned int rd : 5, 1020 + __BITFIELD_FIELD(unsigned int fd : 5, 1021 + __BITFIELD_FIELD(unsigned int func : 6, 1022 + ;)))))) 1023 + }; 1024 + 1015 1025 /* 1016 1026 * MIPS16e instruction formats (16-bit length) 1017 1027 */ ··· 1124 1114 struct mm16_r5_format mm16_r5_format; 1125 1115 struct loongson3_lswc2_format loongson3_lswc2_format; 1126 1116 struct loongson3_lsdc2_format loongson3_lsdc2_format; 1117 + struct loongson3_lscsr_format loongson3_lscsr_format; 1127 1118 }; 1128 1119 1129 1120 union mips16e_instruction {
+1
arch/mips/kvm/mips.c
··· 67 67 VCPU_STAT("vz_ghfc", vz_ghfc_exits), 68 68 VCPU_STAT("vz_gpa", vz_gpa_exits), 69 69 VCPU_STAT("vz_resvd", vz_resvd_exits), 70 + VCPU_STAT("vz_cpucfg", vz_cpucfg_exits), 70 71 #endif 71 72 VCPU_STAT("halt_successful_poll", halt_successful_poll), 72 73 VCPU_STAT("halt_attempted_poll", halt_attempted_poll),
+77
arch/mips/kvm/vz.c
··· 29 29 #include <linux/kvm_host.h> 30 30 31 31 #include "interrupt.h" 32 + #include "loongson_regs.h" 32 33 33 34 #include "trace.h" 34 35 ··· 1093 1092 return EMULATE_FAIL; 1094 1093 } 1095 1094 1095 + #ifdef CONFIG_CPU_LOONGSON64 1096 + static enum emulation_result kvm_vz_gpsi_lwc2(union mips_instruction inst, 1097 + u32 *opc, u32 cause, 1098 + struct kvm_run *run, 1099 + struct kvm_vcpu *vcpu) 1100 + { 1101 + unsigned int rs, rd; 1102 + unsigned int hostcfg; 1103 + unsigned long curr_pc; 1104 + enum emulation_result er = EMULATE_DONE; 1105 + 1106 + /* 1107 + * Update PC and hold onto current PC in case there is 1108 + * an error and we want to rollback the PC 1109 + */ 1110 + curr_pc = vcpu->arch.pc; 1111 + er = update_pc(vcpu, cause); 1112 + if (er == EMULATE_FAIL) 1113 + return er; 1114 + 1115 + rs = inst.loongson3_lscsr_format.rs; 1116 + rd = inst.loongson3_lscsr_format.rd; 1117 + switch (inst.loongson3_lscsr_format.fr) { 1118 + case 0x8: /* Read CPUCFG */ 1119 + ++vcpu->stat.vz_cpucfg_exits; 1120 + hostcfg = read_cpucfg(vcpu->arch.gprs[rs]); 1121 + 1122 + switch (vcpu->arch.gprs[rs]) { 1123 + case LOONGSON_CFG0: 1124 + vcpu->arch.gprs[rd] = 0x14c000; 1125 + break; 1126 + case LOONGSON_CFG1: 1127 + hostcfg &= (LOONGSON_CFG1_FP | LOONGSON_CFG1_MMI | 1128 + LOONGSON_CFG1_MSA1 | LOONGSON_CFG1_MSA2 | 1129 + LOONGSON_CFG1_SFBP); 1130 + vcpu->arch.gprs[rd] = hostcfg; 1131 + break; 1132 + case LOONGSON_CFG2: 1133 + hostcfg &= (LOONGSON_CFG2_LEXT1 | LOONGSON_CFG2_LEXT2 | 1134 + LOONGSON_CFG2_LEXT3 | LOONGSON_CFG2_LSPW); 1135 + vcpu->arch.gprs[rd] = hostcfg; 1136 + break; 1137 + case LOONGSON_CFG3: 1138 + vcpu->arch.gprs[rd] = hostcfg; 1139 + break; 1140 + default: 1141 + /* Don't export any other advanced features to guest */ 1142 + vcpu->arch.gprs[rd] = 0; 1143 + break; 1144 + } 1145 + break; 1146 + 1147 + default: 1148 + kvm_err("lwc2 emulate not impl %d rs %lx @%lx\n", 1149 + inst.loongson3_lscsr_format.fr, vcpu->arch.gprs[rs], curr_pc); 1150 + er = EMULATE_FAIL; 1151 + break; 1152 + } 1153 + 1154 + /* Rollback PC only if emulation was unsuccessful */ 1155 + if (er == EMULATE_FAIL) { 1156 + kvm_err("[%#lx]%s: unsupported lwc2 instruction 0x%08x 0x%08x\n", 1157 + curr_pc, __func__, inst.word, inst.loongson3_lscsr_format.fr); 1158 + 1159 + vcpu->arch.pc = curr_pc; 1160 + } 1161 + 1162 + return er; 1163 + } 1164 + #endif 1165 + 1096 1166 static enum emulation_result kvm_trap_vz_handle_gpsi(u32 cause, u32 *opc, 1097 1167 struct kvm_vcpu *vcpu) 1098 1168 { ··· 1191 1119 case cache_op: 1192 1120 trace_kvm_exit(vcpu, KVM_TRACE_EXIT_CACHE); 1193 1121 er = kvm_vz_gpsi_cache(inst, opc, cause, run, vcpu); 1122 + break; 1123 + #endif 1124 + #ifdef CONFIG_CPU_LOONGSON64 1125 + case lwc2_op: 1126 + er = kvm_vz_gpsi_lwc2(inst, opc, cause, run, vcpu); 1194 1127 break; 1195 1128 #endif 1196 1129 case spec3_op: