Message ID | 1588500367-1056-14-git-send-email-chenhc@lemote.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | KVM: MIPS: Add Loongson-3 support (Host Side) | expand |
нед, 3. мај 2020. у 12:16 Huacai Chen <chenhc@lemote.com> је написао/ла: > > 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@lemote.com> > Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com> > --- > 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@gmail.com>
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; }
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@lemote.com> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com> --- arch/mips/kvm/emulate.c | 480 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 470 insertions(+), 10 deletions(-)