aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Lendacky <thomas.lendacky@amd.com>2016-12-14 14:59:23 -0500
committerRadim Krčmář <rkrcmar@redhat.com>2017-01-09 08:47:58 -0500
commit0f89b207b04a1a399e19d35293658e3a571da3d7 (patch)
treec2552c3c7a7a33564c36b4e469c9da7191fe5836
parent5bd5db385b3e13c702365574c0b7350c6ea45e84 (diff)
kvm: svm: Use the hardware provided GPA instead of page walk
When a guest causes a NPF which requires emulation, KVM sometimes walks the guest page tables to translate the GVA to a GPA. This is unnecessary most of the time on AMD hardware since the hardware provides the GPA in EXITINFO2. The only exception cases involve string operations involving rep or operations that use two memory locations. With rep, the GPA will only be the value of the initial NPF and with dual memory locations we won't know which memory address was translated into EXITINFO2. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Reviewed-by: Borislav Petkov <bp@suse.de> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm_emulate.h1
-rw-r--r--arch/x86/include/asm/kvm_host.h3
-rw-r--r--arch/x86/kvm/emulate.c20
-rw-r--r--arch/x86/kvm/svm.c2
-rw-r--r--arch/x86/kvm/x86.c45
5 files changed, 57 insertions, 14 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index e9cd7befcb76..3e8c287090e4 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -441,5 +441,6 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
441int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq); 441int emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq);
442void emulator_invalidate_register_cache(struct x86_emulate_ctxt *ctxt); 442void emulator_invalidate_register_cache(struct x86_emulate_ctxt *ctxt);
443void emulator_writeback_register_cache(struct x86_emulate_ctxt *ctxt); 443void emulator_writeback_register_cache(struct x86_emulate_ctxt *ctxt);
444bool emulator_can_use_gpa(struct x86_emulate_ctxt *ctxt);
444 445
445#endif /* _ASM_X86_KVM_X86_EMULATE_H */ 446#endif /* _ASM_X86_KVM_X86_EMULATE_H */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 99a71d90b6ae..0419e114f27b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -675,6 +675,9 @@ struct kvm_vcpu_arch {
675 675
676 int pending_ioapic_eoi; 676 int pending_ioapic_eoi;
677 int pending_external_vector; 677 int pending_external_vector;
678
679 /* GPA available (AMD only) */
680 bool gpa_available;
678}; 681};
679 682
680struct kvm_lpage_info { 683struct kvm_lpage_info {
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 56628a44668b..2b8349a2b14b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -173,6 +173,7 @@
173#define NearBranch ((u64)1 << 52) /* Near branches */ 173#define NearBranch ((u64)1 << 52) /* Near branches */
174#define No16 ((u64)1 << 53) /* No 16 bit operand */ 174#define No16 ((u64)1 << 53) /* No 16 bit operand */
175#define IncSP ((u64)1 << 54) /* SP is incremented before ModRM calc */ 175#define IncSP ((u64)1 << 54) /* SP is incremented before ModRM calc */
176#define TwoMemOp ((u64)1 << 55) /* Instruction has two memory operand */
176 177
177#define DstXacc (DstAccLo | SrcAccHi | SrcWrite) 178#define DstXacc (DstAccLo | SrcAccHi | SrcWrite)
178 179
@@ -4256,7 +4257,7 @@ static const struct opcode group1[] = {
4256}; 4257};
4257 4258
4258static const struct opcode group1A[] = { 4259static const struct opcode group1A[] = {
4259 I(DstMem | SrcNone | Mov | Stack | IncSP, em_pop), N, N, N, N, N, N, N, 4260 I(DstMem | SrcNone | Mov | Stack | IncSP | TwoMemOp, em_pop), N, N, N, N, N, N, N,
4260}; 4261};
4261 4262
4262static const struct opcode group2[] = { 4263static const struct opcode group2[] = {
@@ -4294,7 +4295,7 @@ static const struct opcode group5[] = {
4294 I(SrcMemFAddr | ImplicitOps, em_call_far), 4295 I(SrcMemFAddr | ImplicitOps, em_call_far),
4295 I(SrcMem | NearBranch, em_jmp_abs), 4296 I(SrcMem | NearBranch, em_jmp_abs),
4296 I(SrcMemFAddr | ImplicitOps, em_jmp_far), 4297 I(SrcMemFAddr | ImplicitOps, em_jmp_far),
4297 I(SrcMem | Stack, em_push), D(Undefined), 4298 I(SrcMem | Stack | TwoMemOp, em_push), D(Undefined),
4298}; 4299};
4299 4300
4300static const struct opcode group6[] = { 4301static const struct opcode group6[] = {
@@ -4514,8 +4515,8 @@ static const struct opcode opcode_table[256] = {
4514 /* 0xA0 - 0xA7 */ 4515 /* 0xA0 - 0xA7 */
4515 I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov), 4516 I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov),
4516 I2bv(DstMem | SrcAcc | Mov | MemAbs | PageTable, em_mov), 4517 I2bv(DstMem | SrcAcc | Mov | MemAbs | PageTable, em_mov),
4517 I2bv(SrcSI | DstDI | Mov | String, em_mov), 4518 I2bv(SrcSI | DstDI | Mov | String | TwoMemOp, em_mov),
4518 F2bv(SrcSI | DstDI | String | NoWrite, em_cmp_r), 4519 F2bv(SrcSI | DstDI | String | NoWrite | TwoMemOp, em_cmp_r),
4519 /* 0xA8 - 0xAF */ 4520 /* 0xA8 - 0xAF */
4520 F2bv(DstAcc | SrcImm | NoWrite, em_test), 4521 F2bv(DstAcc | SrcImm | NoWrite, em_test),
4521 I2bv(SrcAcc | DstDI | Mov | String, em_mov), 4522 I2bv(SrcAcc | DstDI | Mov | String, em_mov),
@@ -5629,3 +5630,14 @@ void emulator_writeback_register_cache(struct x86_emulate_ctxt *ctxt)
5629{ 5630{
5630 writeback_registers(ctxt); 5631 writeback_registers(ctxt);
5631} 5632}
5633
5634bool emulator_can_use_gpa(struct x86_emulate_ctxt *ctxt)
5635{
5636 if (ctxt->rep_prefix && (ctxt->d & String))
5637 return false;
5638
5639 if (ctxt->d & TwoMemOp)
5640 return false;
5641
5642 return true;
5643}
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 08a4d3ab3455..d0414f054bdf 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -4182,6 +4182,8 @@ static int handle_exit(struct kvm_vcpu *vcpu)
4182 4182
4183 trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM); 4183 trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM);
4184 4184
4185 vcpu->arch.gpa_available = (exit_code == SVM_EXIT_NPF);
4186
4185 if (!is_cr_intercept(svm, INTERCEPT_CR0_WRITE)) 4187 if (!is_cr_intercept(svm, INTERCEPT_CR0_WRITE))
4186 vcpu->arch.cr0 = svm->vmcb->save.cr0; 4188 vcpu->arch.cr0 = svm->vmcb->save.cr0;
4187 if (npt_enabled) 4189 if (npt_enabled)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index c3ee5e29ea2a..edff19d1df97 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4462,6 +4462,21 @@ out:
4462} 4462}
4463EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system); 4463EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system);
4464 4464
4465static int vcpu_is_mmio_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
4466 gpa_t gpa, bool write)
4467{
4468 /* For APIC access vmexit */
4469 if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
4470 return 1;
4471
4472 if (vcpu_match_mmio_gpa(vcpu, gpa)) {
4473 trace_vcpu_match_mmio(gva, gpa, write, true);
4474 return 1;
4475 }
4476
4477 return 0;
4478}
4479
4465static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, 4480static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
4466 gpa_t *gpa, struct x86_exception *exception, 4481 gpa_t *gpa, struct x86_exception *exception,
4467 bool write) 4482 bool write)
@@ -4488,16 +4503,7 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva,
4488 if (*gpa == UNMAPPED_GVA) 4503 if (*gpa == UNMAPPED_GVA)
4489 return -1; 4504 return -1;
4490 4505
4491 /* For APIC access vmexit */ 4506 return vcpu_is_mmio_gpa(vcpu, gva, *gpa, write);
4492 if ((*gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
4493 return 1;
4494
4495 if (vcpu_match_mmio_gpa(vcpu, *gpa)) {
4496 trace_vcpu_match_mmio(gva, *gpa, write, true);
4497 return 1;
4498 }
4499
4500 return 0;
4501} 4507}
4502 4508
4503int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, 4509int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -4594,6 +4600,22 @@ static int emulator_read_write_onepage(unsigned long addr, void *val,
4594 int handled, ret; 4600 int handled, ret;
4595 bool write = ops->write; 4601 bool write = ops->write;
4596 struct kvm_mmio_fragment *frag; 4602 struct kvm_mmio_fragment *frag;
4603 struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
4604
4605 /*
4606 * If the exit was due to a NPF we may already have a GPA.
4607 * If the GPA is present, use it to avoid the GVA to GPA table walk.
4608 * Note, this cannot be used on string operations since string
4609 * operation using rep will only have the initial GPA from the NPF
4610 * occurred.
4611 */
4612 if (vcpu->arch.gpa_available &&
4613 emulator_can_use_gpa(ctxt) &&
4614 vcpu_is_mmio_gpa(vcpu, addr, exception->address, write) &&
4615 (addr & ~PAGE_MASK) == (exception->address & ~PAGE_MASK)) {
4616 gpa = exception->address;
4617 goto mmio;
4618 }
4597 4619
4598 ret = vcpu_mmio_gva_to_gpa(vcpu, addr, &gpa, exception, write); 4620 ret = vcpu_mmio_gva_to_gpa(vcpu, addr, &gpa, exception, write);
4599 4621
@@ -5610,6 +5632,9 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
5610 } 5632 }
5611 5633
5612restart: 5634restart:
5635 /* Save the faulting GPA (cr2) in the address field */
5636 ctxt->exception.address = cr2;
5637
5613 r = x86_emulate_insn(ctxt); 5638 r = x86_emulate_insn(ctxt);
5614 5639
5615 if (r == EMULATION_INTERCEPTED) 5640 if (r == EMULATION_INTERCEPTED)