in kvm/emulate.c [1270:1509]
enum emulation_result kvm_mips_emulate_load(union mips_instruction inst,
u32 cause, struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
int r;
enum emulation_result er;
unsigned long curr_pc;
u32 op, rt;
unsigned int imme;
rt = inst.i_format.rt;
op = inst.i_format.opcode;
/*
* Find the resume PC now while we have safe and easy access to the
* prior branch instruction, and save it for
* kvm_mips_complete_mmio_load() to restore later.
*/
curr_pc = vcpu->arch.pc;
er = update_pc(vcpu, cause);
if (er == EMULATE_FAIL)
return er;
vcpu->arch.io_pc = vcpu->arch.pc;
vcpu->arch.pc = curr_pc;
vcpu->arch.io_gpr = rt;
run->mmio.phys_addr = kvm_mips_callbacks->gva_to_gpa(
vcpu->arch.host_cp0_badvaddr);
if (run->mmio.phys_addr == KVM_INVALID_ADDR)
return EMULATE_FAIL;
vcpu->mmio_needed = 2; /* signed */
switch (op) {
#if defined(CONFIG_64BIT)
case ld_op:
run->mmio.len = 8;
break;
case lwu_op:
vcpu->mmio_needed = 1; /* unsigned */
fallthrough;
#endif
case lw_op:
run->mmio.len = 4;
break;
case lhu_op:
vcpu->mmio_needed = 1; /* unsigned */
fallthrough;
case lh_op:
run->mmio.len = 2;
break;
case lbu_op:
vcpu->mmio_needed = 1; /* unsigned */
fallthrough;
case lb_op:
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;
#if defined(CONFIG_64BIT)
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;
#endif
#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 Extended 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);
vcpu->mmio_needed = 0;
return EMULATE_FAIL;
}
run->mmio.is_write = 0;
vcpu->mmio_is_write = 0;
r = kvm_io_bus_read(vcpu, KVM_MMIO_BUS,
run->mmio.phys_addr, run->mmio.len, run->mmio.data);
if (!r) {
kvm_mips_complete_mmio_load(vcpu);
vcpu->mmio_needed = 0;
return EMULATE_DONE;
}
return EMULATE_DO_MMIO;
}