aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kvm/emulate.c
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2016-10-25 11:11:12 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2016-10-26 07:43:55 -0400
commite1e575f6b026734be3b1f075e780e91ab08ca541 (patch)
treec104b417fdee65ed848470a75cc459532df9cf98 /arch/mips/kvm/emulate.c
parentede5f3e7b54a4347be4d8525269eae50902bd7cd (diff)
KVM: MIPS: Precalculate MMIO load resume PC
The advancing of the PC when completing an MMIO load is done before re-entering the guest, i.e. before restoring the guest ASID. However if the load is in a branch delay slot it may need to access guest code to read the prior branch instruction. This isn't safe in TLB mapped code at the moment, nor in the future when we'll access unmapped guest segments using direct user accessors too, as it could read the branch from host user memory instead. Therefore calculate the resume PC in advance while we're still in the right context and save it in the new vcpu->arch.io_pc (replacing the no longer needed vcpu->arch.pending_load_cause), and restore it on MMIO completion. Fixes: e685c689f3a8 ("KVM/MIPS32: Privileged instruction/target branch emulation.") Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: "Radim Krčmář <rkrcmar@redhat.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Cc: <stable@vger.kernel.org> # 3.10.x- Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/mips/kvm/emulate.c')
-rw-r--r--arch/mips/kvm/emulate.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index c45ef0f13dfa..aa0937423e28 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -1528,13 +1528,25 @@ enum emulation_result kvm_mips_emulate_load(union mips_instruction inst,
1528 struct kvm_vcpu *vcpu) 1528 struct kvm_vcpu *vcpu)
1529{ 1529{
1530 enum emulation_result er = EMULATE_DO_MMIO; 1530 enum emulation_result er = EMULATE_DO_MMIO;
1531 unsigned long curr_pc;
1531 u32 op, rt; 1532 u32 op, rt;
1532 u32 bytes; 1533 u32 bytes;
1533 1534
1534 rt = inst.i_format.rt; 1535 rt = inst.i_format.rt;
1535 op = inst.i_format.opcode; 1536 op = inst.i_format.opcode;
1536 1537
1537 vcpu->arch.pending_load_cause = cause; 1538 /*
1539 * Find the resume PC now while we have safe and easy access to the
1540 * prior branch instruction, and save it for
1541 * kvm_mips_complete_mmio_load() to restore later.
1542 */
1543 curr_pc = vcpu->arch.pc;
1544 er = update_pc(vcpu, cause);
1545 if (er == EMULATE_FAIL)
1546 return er;
1547 vcpu->arch.io_pc = vcpu->arch.pc;
1548 vcpu->arch.pc = curr_pc;
1549
1538 vcpu->arch.io_gpr = rt; 1550 vcpu->arch.io_gpr = rt;
1539 1551
1540 switch (op) { 1552 switch (op) {
@@ -2494,9 +2506,8 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
2494 goto done; 2506 goto done;
2495 } 2507 }
2496 2508
2497 er = update_pc(vcpu, vcpu->arch.pending_load_cause); 2509 /* Restore saved resume PC */
2498 if (er == EMULATE_FAIL) 2510 vcpu->arch.pc = vcpu->arch.io_pc;
2499 return er;
2500 2511
2501 switch (run->mmio.len) { 2512 switch (run->mmio.len) {
2502 case 4: 2513 case 4:
@@ -2518,11 +2529,6 @@ enum emulation_result kvm_mips_complete_mmio_load(struct kvm_vcpu *vcpu,
2518 break; 2529 break;
2519 } 2530 }
2520 2531
2521 if (vcpu->arch.pending_load_cause & CAUSEF_BD)
2522 kvm_debug("[%#lx] Completing %d byte BD Load to gpr %d (0x%08lx) type %d\n",
2523 vcpu->arch.pc, run->mmio.len, vcpu->arch.io_gpr, *gpr,
2524 vcpu->mmio_needed);
2525
2526done: 2532done:
2527 return er; 2533 return er;
2528} 2534}