Skip to content

Commit 7f2a83f

Browse files
chenhuacaibonzini
authored andcommitted
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 <[email protected]> Signed-off-by: Huacai Chen <[email protected]> Co-developed-by: Jiaxun Yang <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent f21db30 commit 7f2a83f

File tree

4 files changed

+92
-0
lines changed

4 files changed

+92
-0
lines changed

arch/mips/include/asm/kvm_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ struct kvm_vcpu_stat {
173173
u64 vz_ghfc_exits;
174174
u64 vz_gpa_exits;
175175
u64 vz_resvd_exits;
176+
#ifdef CONFIG_CPU_LOONGSON64
177+
u64 vz_cpucfg_exits;
178+
#endif
176179
#endif
177180
u64 halt_successful_poll;
178181
u64 halt_attempted_poll;

arch/mips/include/uapi/asm/inst.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,16 @@ struct loongson3_lsdc2_format { /* Loongson-3 overridden ldc2/sdc2 Load/Store fo
10121012
;))))))
10131013
};
10141014

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+
10151025
/*
10161026
* MIPS16e instruction formats (16-bit length)
10171027
*/
@@ -1114,6 +1124,7 @@ union mips_instruction {
11141124
struct mm16_r5_format mm16_r5_format;
11151125
struct loongson3_lswc2_format loongson3_lswc2_format;
11161126
struct loongson3_lsdc2_format loongson3_lsdc2_format;
1127+
struct loongson3_lscsr_format loongson3_lscsr_format;
11171128
};
11181129

11191130
union mips16e_instruction {

arch/mips/kvm/mips.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
6767
VCPU_STAT("vz_ghfc", vz_ghfc_exits),
6868
VCPU_STAT("vz_gpa", vz_gpa_exits),
6969
VCPU_STAT("vz_resvd", vz_resvd_exits),
70+
VCPU_STAT("vz_cpucfg", vz_cpucfg_exits),
7071
#endif
7172
VCPU_STAT("halt_successful_poll", halt_successful_poll),
7273
VCPU_STAT("halt_attempted_poll", halt_attempted_poll),

arch/mips/kvm/vz.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/kvm_host.h>
3030

3131
#include "interrupt.h"
32+
#include "loongson_regs.h"
3233

3334
#include "trace.h"
3435

@@ -1092,6 +1093,77 @@ static enum emulation_result kvm_vz_gpsi_cache(union mips_instruction inst,
10921093
return EMULATE_FAIL;
10931094
}
10941095

1096+
#ifdef CONFIG_CPU_LOONGSON64
1097+
static enum emulation_result kvm_vz_gpsi_lwc2(union mips_instruction inst,
1098+
u32 *opc, u32 cause,
1099+
struct kvm_run *run,
1100+
struct kvm_vcpu *vcpu)
1101+
{
1102+
unsigned int rs, rd;
1103+
unsigned int hostcfg;
1104+
unsigned long curr_pc;
1105+
enum emulation_result er = EMULATE_DONE;
1106+
1107+
/*
1108+
* Update PC and hold onto current PC in case there is
1109+
* an error and we want to rollback the PC
1110+
*/
1111+
curr_pc = vcpu->arch.pc;
1112+
er = update_pc(vcpu, cause);
1113+
if (er == EMULATE_FAIL)
1114+
return er;
1115+
1116+
rs = inst.loongson3_lscsr_format.rs;
1117+
rd = inst.loongson3_lscsr_format.rd;
1118+
switch (inst.loongson3_lscsr_format.fr) {
1119+
case 0x8: /* Read CPUCFG */
1120+
++vcpu->stat.vz_cpucfg_exits;
1121+
hostcfg = read_cpucfg(vcpu->arch.gprs[rs]);
1122+
1123+
switch (vcpu->arch.gprs[rs]) {
1124+
case LOONGSON_CFG0:
1125+
vcpu->arch.gprs[rd] = 0x14c000;
1126+
break;
1127+
case LOONGSON_CFG1:
1128+
hostcfg &= (LOONGSON_CFG1_FP | LOONGSON_CFG1_MMI |
1129+
LOONGSON_CFG1_MSA1 | LOONGSON_CFG1_MSA2 |
1130+
LOONGSON_CFG1_SFBP);
1131+
vcpu->arch.gprs[rd] = hostcfg;
1132+
break;
1133+
case LOONGSON_CFG2:
1134+
hostcfg &= (LOONGSON_CFG2_LEXT1 | LOONGSON_CFG2_LEXT2 |
1135+
LOONGSON_CFG2_LEXT3 | LOONGSON_CFG2_LSPW);
1136+
vcpu->arch.gprs[rd] = hostcfg;
1137+
break;
1138+
case LOONGSON_CFG3:
1139+
vcpu->arch.gprs[rd] = hostcfg;
1140+
break;
1141+
default:
1142+
/* Don't export any other advanced features to guest */
1143+
vcpu->arch.gprs[rd] = 0;
1144+
break;
1145+
}
1146+
break;
1147+
1148+
default:
1149+
kvm_err("lwc2 emulate not impl %d rs %lx @%lx\n",
1150+
inst.loongson3_lscsr_format.fr, vcpu->arch.gprs[rs], curr_pc);
1151+
er = EMULATE_FAIL;
1152+
break;
1153+
}
1154+
1155+
/* Rollback PC only if emulation was unsuccessful */
1156+
if (er == EMULATE_FAIL) {
1157+
kvm_err("[%#lx]%s: unsupported lwc2 instruction 0x%08x 0x%08x\n",
1158+
curr_pc, __func__, inst.word, inst.loongson3_lscsr_format.fr);
1159+
1160+
vcpu->arch.pc = curr_pc;
1161+
}
1162+
1163+
return er;
1164+
}
1165+
#endif
1166+
10951167
static enum emulation_result kvm_trap_vz_handle_gpsi(u32 cause, u32 *opc,
10961168
struct kvm_vcpu *vcpu)
10971169
{
@@ -1120,6 +1192,11 @@ static enum emulation_result kvm_trap_vz_handle_gpsi(u32 cause, u32 *opc,
11201192
trace_kvm_exit(vcpu, KVM_TRACE_EXIT_CACHE);
11211193
er = kvm_vz_gpsi_cache(inst, opc, cause, run, vcpu);
11221194
break;
1195+
#endif
1196+
#ifdef CONFIG_CPU_LOONGSON64
1197+
case lwc2_op:
1198+
er = kvm_vz_gpsi_lwc2(inst, opc, cause, run, vcpu);
1199+
break;
11231200
#endif
11241201
case spec3_op:
11251202
switch (inst.spec3_format.func) {

0 commit comments

Comments
 (0)