нед, 3. мај 2020. у 12:16 Huacai Chen <chenhc@xxxxxxxxxx> је написао/ла: > > This patch add more MMIO load/store instructions emulation, which can > be observed in QXL and some other device drivers: > > 1, LWL, LWR, LDW, LDR, SWL, SWR, SDL and SDR for all MIPS; > 2, GSLBX, GSLHX, GSLWX, GSLDX, GSSBX, GSSHX, GSSWX and GSSDX for > Loongson-3. > > Signed-off-by: Huacai Chen <chenhc@xxxxxxxxxx> > Co-developed-by: Jiaxun Yang <jiaxun.yang@xxxxxxxxxxx> > --- > arch/mips/kvm/emulate.c | 480 +++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 470 insertions(+), 10 deletions(-) > > diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c > index 3946499..71316fa 100644 > --- a/arch/mips/kvm/emulate.c > +++ b/arch/mips/kvm/emulate.c > @@ -1604,6 +1604,7 @@ enum emulation_result kvm_mips_emulate_store(union mips_instruction inst, > enum emulation_result er; > u32 rt; > void *data = run->mmio.data; > + unsigned int imme; > unsigned long curr_pc; > > /* > @@ -1661,6 +1662,211 @@ enum emulation_result kvm_mips_emulate_store(union mips_instruction inst, > vcpu->arch.gprs[rt], *(u8 *)data); > break; > > + case swl_op: > + run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa( > + vcpu->arch.host_cp0_badvaddr) & (~0x3); > + run->mmio.len = 4; > + imme = vcpu->arch.host_cp0_badvaddr & 0x3; > + switch (imme) { > + case 0: > + *(u32 *)data = ((*(u32 *)data) & 0xffffff00) | > + (vcpu->arch.gprs[rt] >> 24); > + break; > + case 1: > + *(u32 *)data = ((*(u32 *)data) & 0xffff0000) | > + (vcpu->arch.gprs[rt] >> 16); > + break; > + case 2: > + *(u32 *)data = ((*(u32 *)data) & 0xff000000) | > + (vcpu->arch.gprs[rt] >> 8); > + break; > + case 3: > + *(u32 *)data = vcpu->arch.gprs[rt]; > + break; > + default: > + break; > + } > + > + kvm_debug("[%#lx] OP_SWL: eaddr: %#lx, gpr: %#lx, data: %#x\n", > + vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr, > + vcpu->arch.gprs[rt], *(u32 *)data); > + break; > + > + case swr_op: > + run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa( > + vcpu->arch.host_cp0_badvaddr) & (~0x3); > + run->mmio.len = 4; > + imme = vcpu->arch.host_cp0_badvaddr & 0x3; > + switch (imme) { > + case 0: > + *(u32 *)data = vcpu->arch.gprs[rt]; > + break; > + case 1: > + *(u32 *)data = ((*(u32 *)data) & 0xff) | > + (vcpu->arch.gprs[rt] << 8); > + break; > + case 2: > + *(u32 *)data = ((*(u32 *)data) & 0xffff) | > + (vcpu->arch.gprs[rt] << 16); > + break; > + case 3: > + *(u32 *)data = ((*(u32 *)data) & 0xffffff) | > + (vcpu->arch.gprs[rt] << 24); > + break; > + default: > + break; > + } > + > + kvm_debug("[%#lx] OP_SWR: eaddr: %#lx, gpr: %#lx, data: %#x\n", > + vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr, > + vcpu->arch.gprs[rt], *(u32 *)data); > + break; > + > + case sdl_op: > + run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa( > + vcpu->arch.host_cp0_badvaddr) & (~0x7); > + > + run->mmio.len = 8; > + imme = vcpu->arch.host_cp0_badvaddr & 0x7; > + switch (imme) { > + case 0: > + *(u64 *)data = ((*(u64 *)data) & 0xffffffffffffff00) | > + ((vcpu->arch.gprs[rt] >> 56) & 0xff); > + break; > + case 1: > + *(u64 *)data = ((*(u64 *)data) & 0xffffffffffff0000) | > + ((vcpu->arch.gprs[rt] >> 48) & 0xffff); > + break; > + case 2: > + *(u64 *)data = ((*(u64 *)data) & 0xffffffffff000000) | > + ((vcpu->arch.gprs[rt] >> 40) & 0xffffff); > + break; > + case 3: > + *(u64 *)data = ((*(u64 *)data) & 0xffffffff00000000) | > + ((vcpu->arch.gprs[rt] >> 32) & 0xffffffff); > + break; > + case 4: > + *(u64 *)data = ((*(u64 *)data) & 0xffffff0000000000) | > + ((vcpu->arch.gprs[rt] >> 24) & 0xffffffffff); > + break; > + case 5: > + *(u64 *)data = ((*(u64 *)data) & 0xffff000000000000) | > + ((vcpu->arch.gprs[rt] >> 16) & 0xffffffffffff); > + break; > + case 6: > + *(u64 *)data = ((*(u64 *)data) & 0xff00000000000000) | > + ((vcpu->arch.gprs[rt] >> 8) & 0xffffffffffffff); > + break; > + case 7: > + *(u64 *)data = vcpu->arch.gprs[rt]; > + break; > + default: > + break; > + } > + > + kvm_debug("[%#lx] OP_SDL: eaddr: %#lx, gpr: %#lx, data: %llx\n", > + vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr, > + vcpu->arch.gprs[rt], *(u64 *)data); > + break; > + > + case sdr_op: > + run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa( > + vcpu->arch.host_cp0_badvaddr) & (~0x7); > + > + run->mmio.len = 8; > + imme = vcpu->arch.host_cp0_badvaddr & 0x7; > + switch (imme) { > + case 0: > + *(u64 *)data = vcpu->arch.gprs[rt]; > + break; > + case 1: > + *(u64 *)data = ((*(u64 *)data) & 0xff) | > + (vcpu->arch.gprs[rt] << 8); > + break; > + case 2: > + *(u64 *)data = ((*(u64 *)data) & 0xffff) | > + (vcpu->arch.gprs[rt] << 16); > + break; > + case 3: > + *(u64 *)data = ((*(u64 *)data) & 0xffffff) | > + (vcpu->arch.gprs[rt] << 24); > + break; > + case 4: > + *(u64 *)data = ((*(u64 *)data) & 0xffffffff) | > + (vcpu->arch.gprs[rt] << 32); > + break; > + case 5: > + *(u64 *)data = ((*(u64 *)data) & 0xffffffffff) | > + (vcpu->arch.gprs[rt] << 40); > + break; > + case 6: > + *(u64 *)data = ((*(u64 *)data) & 0xffffffffffff) | > + (vcpu->arch.gprs[rt] << 48); > + break; > + case 7: > + *(u64 *)data = ((*(u64 *)data) & 0xffffffffffffff) | > + (vcpu->arch.gprs[rt] << 56); > + break; > + default: > + break; > + } > + > + kvm_debug("[%#lx] OP_SDR: eaddr: %#lx, gpr: %#lx, data: %llx\n", > + vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr, > + vcpu->arch.gprs[rt], *(u64 *)data); > + break; > + > +#ifdef CONFIG_CPU_LOONGSON64 > + case sdc2_op: > + rt = inst.loongson3_lsdc2_format.rt; > + switch (inst.loongson3_lsdc2_format.opcode1) { > + /* > + * Loongson-3 overridden sdc2 instructions. > + * opcode1 instruction > + * 0x0 gssbx: store 1 bytes from GPR > + * 0x1 gsshx: store 2 bytes from GPR > + * 0x2 gsswx: store 4 bytes from GPR > + * 0x3 gssdx: store 8 bytes from GPR > + */ > + case 0x0: > + run->mmio.len = 1; > + *(u8 *)data = vcpu->arch.gprs[rt]; > + > + kvm_debug("[%#lx] OP_GSSBX: eaddr: %#lx, gpr: %#lx, data: %#x\n", > + vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr, > + vcpu->arch.gprs[rt], *(u8 *)data); > + break; > + case 0x1: > + run->mmio.len = 2; > + *(u16 *)data = vcpu->arch.gprs[rt]; > + > + kvm_debug("[%#lx] OP_GSSSHX: eaddr: %#lx, gpr: %#lx, data: %#x\n", > + vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr, > + vcpu->arch.gprs[rt], *(u16 *)data); > + break; > + case 0x2: > + run->mmio.len = 4; > + *(u32 *)data = vcpu->arch.gprs[rt]; > + > + kvm_debug("[%#lx] OP_GSSWX: eaddr: %#lx, gpr: %#lx, data: %#x\n", > + vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr, > + vcpu->arch.gprs[rt], *(u32 *)data); > + break; > + case 0x3: > + run->mmio.len = 8; > + *(u64 *)data = vcpu->arch.gprs[rt]; > + > + kvm_debug("[%#lx] OP_GSSDX: eaddr: %#lx, gpr: %#lx, data: %#llx\n", > + vcpu->arch.pc, vcpu->arch.host_cp0_badvaddr, > + vcpu->arch.gprs[rt], *(u64 *)data); > + break; > + default: > + kvm_err("Godson Exteneded GS-Store not yet supported (inst=0x%08x)\n", > + inst.word); > + break; > + } > + break; > +#endif > default: > kvm_err("Store not yet supported (inst=0x%08x)\n", > inst.word); > @@ -1695,6 +1901,7 @@ enum emulation_result kvm_mips_emulate_load(union mips_instruction inst, > enum emulation_result er; > unsigned long curr_pc; > u32 op, rt; > + unsigned int imme; > > rt = inst.i_format.rt; > op = inst.i_format.opcode; > @@ -1747,6 +1954,162 @@ enum emulation_result kvm_mips_emulate_load(union mips_instruction inst, > run->mmio.len = 1; > break; > > + case lwl_op: > + run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa( > + vcpu->arch.host_cp0_badvaddr) & (~0x3); > + > + run->mmio.len = 4; > + imme = vcpu->arch.host_cp0_badvaddr & 0x3; > + switch (imme) { > + case 0: > + vcpu->mmio_needed = 3; /* 1 byte */ > + break; > + case 1: > + vcpu->mmio_needed = 4; /* 2 bytes */ > + break; > + case 2: > + vcpu->mmio_needed = 5; /* 3 bytes */ > + break; > + case 3: > + vcpu->mmio_needed = 6; /* 4 bytes */ > + break; > + default: > + break; > + } > + break; > + > + case lwr_op: > + run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa( > + vcpu->arch.host_cp0_badvaddr) & (~0x3); > + > + run->mmio.len = 4; > + imme = vcpu->arch.host_cp0_badvaddr & 0x3; > + switch (imme) { > + case 0: > + vcpu->mmio_needed = 7; /* 4 bytes */ > + break; > + case 1: > + vcpu->mmio_needed = 8; /* 3 bytes */ > + break; > + case 2: > + vcpu->mmio_needed = 9; /* 2 bytes */ > + break; > + case 3: > + vcpu->mmio_needed = 10; /* 1 byte */ > + break; > + default: > + break; > + } > + break; > + > + case ldl_op: > + run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa( > + vcpu->arch.host_cp0_badvaddr) & (~0x7); > + > + run->mmio.len = 8; > + imme = vcpu->arch.host_cp0_badvaddr & 0x7; > + switch (imme) { > + case 0: > + vcpu->mmio_needed = 11; /* 1 byte */ > + break; > + case 1: > + vcpu->mmio_needed = 12; /* 2 bytes */ > + break; > + case 2: > + vcpu->mmio_needed = 13; /* 3 bytes */ > + break; > + case 3: > + vcpu->mmio_needed = 14; /* 4 bytes */ > + break; > + case 4: > + vcpu->mmio_needed = 15; /* 5 bytes */ > + break; > + case 5: > + vcpu->mmio_needed = 16; /* 6 bytes */ > + break; > + case 6: > + vcpu->mmio_needed = 17; /* 7 bytes */ > + break; > + case 7: > + vcpu->mmio_needed = 18; /* 8 bytes */ > + break; > + default: > + break; > + } > + break; > + > + case ldr_op: > + run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa( > + vcpu->arch.host_cp0_badvaddr) & (~0x7); > + > + run->mmio.len = 8; > + imme = vcpu->arch.host_cp0_badvaddr & 0x7; > + switch (imme) { > + case 0: > + vcpu->mmio_needed = 19; /* 8 bytes */ > + break; > + case 1: > + vcpu->mmio_needed = 20; /* 7 bytes */ > + break; > + case 2: > + vcpu->mmio_needed = 21; /* 6 bytes */ > + break; > + case 3: > + vcpu->mmio_needed = 22; /* 5 bytes */ > + break; > + case 4: > + vcpu->mmio_needed = 23; /* 4 bytes */ > + break; > + case 5: > + vcpu->mmio_needed = 24; /* 3 bytes */ > + break; > + case 6: > + vcpu->mmio_needed = 25; /* 2 bytes */ > + break; > + case 7: > + vcpu->mmio_needed = 26; /* 1 byte */ > + break; > + default: > + break; > + } > + break; > + > +#ifdef CONFIG_CPU_LOONGSON64 > + case ldc2_op: > + rt = inst.loongson3_lsdc2_format.rt; > + switch (inst.loongson3_lsdc2_format.opcode1) { > + /* > + * Loongson-3 overridden ldc2 instructions. > + * opcode1 instruction > + * 0x0 gslbx: store 1 bytes from GPR > + * 0x1 gslhx: store 2 bytes from GPR > + * 0x2 gslwx: store 4 bytes from GPR > + * 0x3 gsldx: store 8 bytes from GPR > + */ > + case 0x0: > + run->mmio.len = 1; > + vcpu->mmio_needed = 27; /* signed */ > + break; > + case 0x1: > + run->mmio.len = 2; > + vcpu->mmio_needed = 28; /* signed */ > + break; > + case 0x2: > + run->mmio.len = 4; > + vcpu->mmio_needed = 29; /* signed */ > + break; > + case 0x3: > + run->mmio.len = 8; > + vcpu->mmio_needed = 30; /* signed */ > + break; > + default: > + kvm_err("Godson Exteneded GS-Load for float not yet supported (inst=0x%08x)\n", > + inst.word); > + break; > + } > + break; > +#endif > + > default: > kvm_err("Load not yet supported (inst=0x%08x)\n", > inst.word); > @@ -2612,28 +2975,125 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu, > > switch (run->mmio.len) { > case 8: > - *gpr = *(s64 *)run->mmio.data; > + switch (vcpu->mmio_needed) { > + case 11: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffffffff) | > + (((*(s64 *)run->mmio.data) & 0xff) << 56); > + break; > + case 12: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffffff) | > + (((*(s64 *)run->mmio.data) & 0xffff) << 48); > + break; > + case 13: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffff) | > + (((*(s64 *)run->mmio.data) & 0xffffff) << 40); > + break; > + case 14: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffff) | > + (((*(s64 *)run->mmio.data) & 0xffffffff) << 32); > + break; > + case 15: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffff) | > + (((*(s64 *)run->mmio.data) & 0xffffffffff) << 24); > + break; > + case 16: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffff) | > + (((*(s64 *)run->mmio.data) & 0xffffffffffff) << 16); > + break; > + case 17: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xff) | > + (((*(s64 *)run->mmio.data) & 0xffffffffffffff) << 8); > + break; > + case 18: > + case 19: > + *gpr = *(s64 *)run->mmio.data; > + break; > + case 20: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xff00000000000000) | > + ((((*(s64 *)run->mmio.data)) >> 8) & 0xffffffffffffff); > + break; > + case 21: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffff000000000000) | > + ((((*(s64 *)run->mmio.data)) >> 16) & 0xffffffffffff); > + break; > + case 22: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffff0000000000) | > + ((((*(s64 *)run->mmio.data)) >> 24) & 0xffffffffff); > + break; > + case 23: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffff00000000) | > + ((((*(s64 *)run->mmio.data)) >> 32) & 0xffffffff); > + break; > + case 24: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffff000000) | > + ((((*(s64 *)run->mmio.data)) >> 40) & 0xffffff); > + break; > + case 25: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffffff0000) | > + ((((*(s64 *)run->mmio.data)) >> 48) & 0xffff); > + break; > + case 26: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffffffffffff00) | > + ((((*(s64 *)run->mmio.data)) >> 56) & 0xff); > + break; > + default: > + *gpr = *(s64 *)run->mmio.data; > + } > break; > > case 4: > - if (vcpu->mmio_needed == 2) > - *gpr = *(s32 *)run->mmio.data; > - else > + switch (vcpu->mmio_needed) { > + case 1: > *gpr = *(u32 *)run->mmio.data; > + break; > + case 2: > + *gpr = *(s32 *)run->mmio.data; > + break; > + case 3: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffff) | > + (((*(s32 *)run->mmio.data) & 0xff) << 24); > + break; > + case 4: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffff) | > + (((*(s32 *)run->mmio.data) & 0xffff) << 16); > + break; > + case 5: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xff) | > + (((*(s32 *)run->mmio.data) & 0xffffff) << 8); > + break; > + case 6: > + case 7: > + *gpr = *(s32 *)run->mmio.data; > + break; > + case 8: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xff000000) | > + ((((*(s32 *)run->mmio.data)) >> 8) & 0xffffff); > + break; > + case 9: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffff0000) | > + ((((*(s32 *)run->mmio.data)) >> 16) & 0xffff); > + break; > + case 10: > + *gpr = (vcpu->arch.gprs[vcpu->arch.io_gpr] & 0xffffff00) | > + ((((*(s32 *)run->mmio.data)) >> 24) & 0xff); > + break; > + default: > + *gpr = *(s32 *)run->mmio.data; > + } > break; > > case 2: > - if (vcpu->mmio_needed == 2) > - *gpr = *(s16 *) run->mmio.data; > - else > + if (vcpu->mmio_needed == 1) > *gpr = *(u16 *)run->mmio.data; > + else > + *gpr = *(s16 *)run->mmio.data; > > break; > case 1: > - if (vcpu->mmio_needed == 2) > - *gpr = *(s8 *) run->mmio.data; > + if (vcpu->mmio_needed == 1) > + *gpr = *(u8 *)run->mmio.data; > else > - *gpr = *(u8 *) run->mmio.data; > + *gpr = *(s8 *)run->mmio.data; > break; > } > > -- > 2.7.0 > Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@xxxxxxxxx>