diff options
author | Andre Przywara <andre.przywara@amd.com> | 2010-12-21 05:12:07 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-01-12 04:31:07 -0500 |
commit | dc25e89e07d5ef31c476117d2c76b34dbb22196c (patch) | |
tree | 9fef452c4bd0704b9d74512a9a58dc5d5b742d53 | |
parent | df4f3108562dc6f6ae6648f2698df7f4c9acf52d (diff) |
KVM: SVM: copy instruction bytes from VMCB
In case of a nested page fault or an intercepted #PF newer SVM
implementations provide a copy of the faulting instruction bytes
in the VMCB.
Use these bytes to feed the instruction emulator and avoid the costly
guest instruction fetch in this case.
Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r-- | arch/x86/include/asm/kvm_emulate.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 9 | ||||
-rw-r--r-- | arch/x86/include/asm/svm.h | 4 | ||||
-rw-r--r-- | arch/x86/kvm/emulate.c | 7 | ||||
-rw-r--r-- | arch/x86/kvm/mmu.c | 5 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 4 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 4 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 6 |
8 files changed, 26 insertions, 15 deletions
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index bf70ecea3974..8e37deb1eb38 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h | |||
@@ -265,7 +265,7 @@ struct x86_emulate_ctxt { | |||
265 | #define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 | 265 | #define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 |
266 | #endif | 266 | #endif |
267 | 267 | ||
268 | int x86_decode_insn(struct x86_emulate_ctxt *ctxt); | 268 | int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len); |
269 | #define EMULATION_FAILED -1 | 269 | #define EMULATION_FAILED -1 |
270 | #define EMULATION_OK 0 | 270 | #define EMULATION_OK 0 |
271 | #define EMULATION_RESTART 1 | 271 | #define EMULATION_RESTART 1 |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index de00b6026b76..6268f6ce6434 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -634,13 +634,13 @@ enum emulation_result { | |||
634 | #define EMULTYPE_NO_DECODE (1 << 0) | 634 | #define EMULTYPE_NO_DECODE (1 << 0) |
635 | #define EMULTYPE_TRAP_UD (1 << 1) | 635 | #define EMULTYPE_TRAP_UD (1 << 1) |
636 | #define EMULTYPE_SKIP (1 << 2) | 636 | #define EMULTYPE_SKIP (1 << 2) |
637 | int x86_emulate_instruction(struct kvm_vcpu *vcpu, | 637 | int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2, |
638 | unsigned long cr2, int emulation_type); | 638 | int emulation_type, void *insn, int insn_len); |
639 | 639 | ||
640 | static inline int emulate_instruction(struct kvm_vcpu *vcpu, | 640 | static inline int emulate_instruction(struct kvm_vcpu *vcpu, |
641 | int emulation_type) | 641 | int emulation_type) |
642 | { | 642 | { |
643 | return x86_emulate_instruction(vcpu, 0, emulation_type); | 643 | return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0); |
644 | } | 644 | } |
645 | 645 | ||
646 | void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); | 646 | void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); |
@@ -721,7 +721,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); | |||
721 | 721 | ||
722 | int kvm_fix_hypercall(struct kvm_vcpu *vcpu); | 722 | int kvm_fix_hypercall(struct kvm_vcpu *vcpu); |
723 | 723 | ||
724 | int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code); | 724 | int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code, |
725 | void *insn, int insn_len); | ||
725 | void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva); | 726 | void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva); |
726 | 727 | ||
727 | void kvm_enable_tdp(void); | 728 | void kvm_enable_tdp(void); |
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index f0ffb8184089..f2b83bc7d784 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h | |||
@@ -83,7 +83,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area { | |||
83 | u32 clean; | 83 | u32 clean; |
84 | u32 reserved_5; | 84 | u32 reserved_5; |
85 | u64 next_rip; | 85 | u64 next_rip; |
86 | u8 reserved_6[816]; | 86 | u8 insn_len; |
87 | u8 insn_bytes[15]; | ||
88 | u8 reserved_6[800]; | ||
87 | }; | 89 | }; |
88 | 90 | ||
89 | 91 | ||
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 36534ecaf596..caf966781d25 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -2610,7 +2610,7 @@ done: | |||
2610 | } | 2610 | } |
2611 | 2611 | ||
2612 | int | 2612 | int |
2613 | x86_decode_insn(struct x86_emulate_ctxt *ctxt) | 2613 | x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) |
2614 | { | 2614 | { |
2615 | struct x86_emulate_ops *ops = ctxt->ops; | 2615 | struct x86_emulate_ops *ops = ctxt->ops; |
2616 | struct decode_cache *c = &ctxt->decode; | 2616 | struct decode_cache *c = &ctxt->decode; |
@@ -2621,7 +2621,10 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt) | |||
2621 | struct operand memop = { .type = OP_NONE }; | 2621 | struct operand memop = { .type = OP_NONE }; |
2622 | 2622 | ||
2623 | c->eip = ctxt->eip; | 2623 | c->eip = ctxt->eip; |
2624 | c->fetch.start = c->fetch.end = c->eip; | 2624 | c->fetch.start = c->eip; |
2625 | c->fetch.end = c->fetch.start + insn_len; | ||
2626 | if (insn_len > 0) | ||
2627 | memcpy(c->fetch.data, insn, insn_len); | ||
2625 | ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS); | 2628 | ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS); |
2626 | 2629 | ||
2627 | switch (mode) { | 2630 | switch (mode) { |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 01c5a104031f..ea6063d9242e 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -3330,7 +3330,8 @@ void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) | |||
3330 | } | 3330 | } |
3331 | } | 3331 | } |
3332 | 3332 | ||
3333 | int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code) | 3333 | int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code, |
3334 | void *insn, int insn_len) | ||
3334 | { | 3335 | { |
3335 | int r; | 3336 | int r; |
3336 | enum emulation_result er; | 3337 | enum emulation_result er; |
@@ -3348,7 +3349,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code) | |||
3348 | if (r) | 3349 | if (r) |
3349 | goto out; | 3350 | goto out; |
3350 | 3351 | ||
3351 | er = x86_emulate_instruction(vcpu, cr2, 0); | 3352 | er = x86_emulate_instruction(vcpu, cr2, 0, insn, insn_len); |
3352 | 3353 | ||
3353 | switch (er) { | 3354 | switch (er) { |
3354 | case EMULATE_DONE: | 3355 | case EMULATE_DONE: |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index a04c01e324b4..af4b911a8bed 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -1527,7 +1527,9 @@ static int pf_interception(struct vcpu_svm *svm) | |||
1527 | trace_kvm_page_fault(fault_address, error_code); | 1527 | trace_kvm_page_fault(fault_address, error_code); |
1528 | if (!npt_enabled && kvm_event_needs_reinjection(&svm->vcpu)) | 1528 | if (!npt_enabled && kvm_event_needs_reinjection(&svm->vcpu)) |
1529 | kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address); | 1529 | kvm_mmu_unprotect_page_virt(&svm->vcpu, fault_address); |
1530 | r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); | 1530 | r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code, |
1531 | svm->vmcb->control.insn_bytes, | ||
1532 | svm->vmcb->control.insn_len); | ||
1531 | break; | 1533 | break; |
1532 | case KVM_PV_REASON_PAGE_NOT_PRESENT: | 1534 | case KVM_PV_REASON_PAGE_NOT_PRESENT: |
1533 | svm->apf_reason = 0; | 1535 | svm->apf_reason = 0; |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index f3c60fb8d95e..736f83955ce9 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -3055,7 +3055,7 @@ static int handle_exception(struct kvm_vcpu *vcpu) | |||
3055 | 3055 | ||
3056 | if (kvm_event_needs_reinjection(vcpu)) | 3056 | if (kvm_event_needs_reinjection(vcpu)) |
3057 | kvm_mmu_unprotect_page_virt(vcpu, cr2); | 3057 | kvm_mmu_unprotect_page_virt(vcpu, cr2); |
3058 | return kvm_mmu_page_fault(vcpu, cr2, error_code); | 3058 | return kvm_mmu_page_fault(vcpu, cr2, error_code, NULL, 0); |
3059 | } | 3059 | } |
3060 | 3060 | ||
3061 | if (vmx->rmode.vm86_active && | 3061 | if (vmx->rmode.vm86_active && |
@@ -3502,7 +3502,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu) | |||
3502 | 3502 | ||
3503 | gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS); | 3503 | gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS); |
3504 | trace_kvm_page_fault(gpa, exit_qualification); | 3504 | trace_kvm_page_fault(gpa, exit_qualification); |
3505 | return kvm_mmu_page_fault(vcpu, gpa, exit_qualification & 0x3); | 3505 | return kvm_mmu_page_fault(vcpu, gpa, exit_qualification & 0x3, NULL, 0); |
3506 | } | 3506 | } |
3507 | 3507 | ||
3508 | static u64 ept_rsvd_mask(u64 spte, int level) | 3508 | static u64 ept_rsvd_mask(u64 spte, int level) |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a6fcb76196b7..7ad9cda8ff36 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4365,7 +4365,9 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva) | |||
4365 | 4365 | ||
4366 | int x86_emulate_instruction(struct kvm_vcpu *vcpu, | 4366 | int x86_emulate_instruction(struct kvm_vcpu *vcpu, |
4367 | unsigned long cr2, | 4367 | unsigned long cr2, |
4368 | int emulation_type) | 4368 | int emulation_type, |
4369 | void *insn, | ||
4370 | int insn_len) | ||
4369 | { | 4371 | { |
4370 | int r; | 4372 | int r; |
4371 | struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; | 4373 | struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode; |
@@ -4386,7 +4388,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, | |||
4386 | vcpu->arch.emulate_ctxt.have_exception = false; | 4388 | vcpu->arch.emulate_ctxt.have_exception = false; |
4387 | vcpu->arch.emulate_ctxt.perm_ok = false; | 4389 | vcpu->arch.emulate_ctxt.perm_ok = false; |
4388 | 4390 | ||
4389 | r = x86_decode_insn(&vcpu->arch.emulate_ctxt); | 4391 | r = x86_decode_insn(&vcpu->arch.emulate_ctxt, insn, insn_len); |
4390 | if (r == X86EMUL_PROPAGATE_FAULT) | 4392 | if (r == X86EMUL_PROPAGATE_FAULT) |
4391 | goto done; | 4393 | goto done; |
4392 | 4394 | ||