aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2016-11-28 13:39:24 -0500
committerJames Hogan <james.hogan@imgtec.com>2017-02-03 10:21:05 -0500
commita1ecc54d7ea629538116351a3ccc7d86bb9a3c69 (patch)
tree3e012830ccb843c32c83eba923be93fbb86b883c
parenta98dd7410370634496aa500abf90ec6336b494ae (diff)
KVM: MIPS/T&E: Don't treat code fetch faults as MMIO
In order to make use of the CP0_BadInstr & CP0_BadInstrP registers we need to be a bit more careful not to treat code fetch faults as MMIO, lest we hit an UNPREDICTABLE register value when we try to emulate the MMIO load instruction but there was no valid instruction word available to the hardware. Add a kvm_is_ifetch_fault() helper to try to figure out whether a load fault was due to a code fetch, and prevent MMIO instruction emulation in that case. 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
-rw-r--r--arch/mips/include/asm/kvm_host.h27
-rw-r--r--arch/mips/kvm/trap_emul.c12
2 files changed, 39 insertions, 0 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h
index 1337abb18e2b..6f68f7545b66 100644
--- a/arch/mips/include/asm/kvm_host.h
+++ b/arch/mips/include/asm/kvm_host.h
@@ -643,6 +643,33 @@ void kvm_trap_emul_invalidate_gva(struct kvm_vcpu *vcpu, unsigned long addr,
643u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu); 643u32 kvm_get_inst(u32 *opc, struct kvm_vcpu *vcpu);
644enum emulation_result update_pc(struct kvm_vcpu *vcpu, u32 cause); 644enum emulation_result update_pc(struct kvm_vcpu *vcpu, u32 cause);
645 645
646/**
647 * kvm_is_ifetch_fault() - Find whether a TLBL exception is due to ifetch fault.
648 * @vcpu: Virtual CPU.
649 *
650 * Returns: Whether the TLBL exception was likely due to an instruction
651 * fetch fault rather than a data load fault.
652 */
653static inline bool kvm_is_ifetch_fault(struct kvm_vcpu_arch *vcpu)
654{
655 unsigned long badvaddr = vcpu->host_cp0_badvaddr;
656 unsigned long epc = msk_isa16_mode(vcpu->pc);
657 u32 cause = vcpu->host_cp0_cause;
658
659 if (epc == badvaddr)
660 return true;
661
662 /*
663 * Branches may be 32-bit or 16-bit instructions.
664 * This isn't exact, but we don't really support MIPS16 or microMIPS yet
665 * in KVM anyway.
666 */
667 if ((cause & CAUSEF_BD) && badvaddr - epc <= 4)
668 return true;
669
670 return false;
671}
672
646extern enum emulation_result kvm_mips_emulate_inst(u32 cause, 673extern enum emulation_result kvm_mips_emulate_inst(u32 cause,
647 u32 *opc, 674 u32 *opc,
648 struct kvm_run *run, 675 struct kvm_run *run,
diff --git a/arch/mips/kvm/trap_emul.c b/arch/mips/kvm/trap_emul.c
index 653850c05b33..ccd56b3ce84b 100644
--- a/arch/mips/kvm/trap_emul.c
+++ b/arch/mips/kvm/trap_emul.c
@@ -178,6 +178,12 @@ static int kvm_trap_emul_handle_tlb_miss(struct kvm_vcpu *vcpu, bool store)
178 } 178 }
179 } else if (KVM_GUEST_KERNEL_MODE(vcpu) 179 } else if (KVM_GUEST_KERNEL_MODE(vcpu)
180 && (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1)) { 180 && (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1)) {
181 /* A code fetch fault doesn't count as an MMIO */
182 if (!store && kvm_is_ifetch_fault(&vcpu->arch)) {
183 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
184 return RESUME_HOST;
185 }
186
181 /* 187 /*
182 * With EVA we may get a TLB exception instead of an address 188 * With EVA we may get a TLB exception instead of an address
183 * error when the guest performs MMIO to KSeg1 addresses. 189 * error when the guest performs MMIO to KSeg1 addresses.
@@ -255,6 +261,12 @@ static int kvm_trap_emul_handle_addr_err_ld(struct kvm_vcpu *vcpu)
255 int ret = RESUME_GUEST; 261 int ret = RESUME_GUEST;
256 262
257 if (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1) { 263 if (KSEGX(badvaddr) == CKSEG0 || KSEGX(badvaddr) == CKSEG1) {
264 /* A code fetch fault doesn't count as an MMIO */
265 if (kvm_is_ifetch_fault(&vcpu->arch)) {
266 run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
267 return RESUME_HOST;
268 }
269
258 kvm_debug("Emulate Load from MMIO space @ %#lx\n", badvaddr); 270 kvm_debug("Emulate Load from MMIO space @ %#lx\n", badvaddr);
259 er = kvm_mips_emulate_inst(cause, opc, run, vcpu); 271 er = kvm_mips_emulate_inst(cause, opc, run, vcpu);
260 if (er == EMULATE_FAIL) { 272 if (er == EMULATE_FAIL) {