Re: [PATCH V3 13/14] KVM: MIPS: Add more MMIO load/store instructions emulation

Aleksandar Markovic
2020-05-08T11:46:55Z

нед, 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>