diff options
author | Kevin Tian <kevin.tian@intel.com> | 2011-08-30 06:56:17 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-09-25 12:52:17 -0400 |
commit | 58fbbf26eb01cf6d92cf18da8d14b3a4af9c4b47 (patch) | |
tree | 738874a15a233eed6e2e18d9cfe99f09482e8b17 | |
parent | 45133ecaaec7aea447afc98cc2c24aac638bbe5c (diff) |
KVM: APIC: avoid instruction emulation for EOI writes
Instruction emulation for EOI writes can be skipped, since sane
guest simply uses MOV instead of string operations. This is a nice
improvement when guest doesn't support x2apic or hyper-V EOI
support.
a single VM bandwidth is observed with ~8% bandwidth improvement
(7.4Gbps->8Gbps), by saving ~5% cycles from EOI emulation.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
<Based on earlier work from>:
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/include/asm/vmx.h | 12 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 9 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 21 |
4 files changed, 43 insertions, 0 deletions
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 2caf290e9895..31f180c21ce9 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h | |||
@@ -350,6 +350,18 @@ enum vmcs_field { | |||
350 | #define DEBUG_REG_ACCESS_REG(eq) (((eq) >> 8) & 0xf) /* 11:8, general purpose reg. */ | 350 | #define DEBUG_REG_ACCESS_REG(eq) (((eq) >> 8) & 0xf) /* 11:8, general purpose reg. */ |
351 | 351 | ||
352 | 352 | ||
353 | /* | ||
354 | * Exit Qualifications for APIC-Access | ||
355 | */ | ||
356 | #define APIC_ACCESS_OFFSET 0xfff /* 11:0, offset within the APIC page */ | ||
357 | #define APIC_ACCESS_TYPE 0xf000 /* 15:12, access type */ | ||
358 | #define TYPE_LINEAR_APIC_INST_READ (0 << 12) | ||
359 | #define TYPE_LINEAR_APIC_INST_WRITE (1 << 12) | ||
360 | #define TYPE_LINEAR_APIC_INST_FETCH (2 << 12) | ||
361 | #define TYPE_LINEAR_APIC_EVENT (3 << 12) | ||
362 | #define TYPE_PHYSICAL_APIC_EVENT (10 << 12) | ||
363 | #define TYPE_PHYSICAL_APIC_INST (15 << 12) | ||
364 | |||
353 | /* segment AR */ | 365 | /* segment AR */ |
354 | #define SEGMENT_AR_L_MASK (1 << 13) | 366 | #define SEGMENT_AR_L_MASK (1 << 13) |
355 | 367 | ||
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 57dcbd4308fa..52645f283870 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -864,6 +864,15 @@ static int apic_mmio_write(struct kvm_io_device *this, | |||
864 | return 0; | 864 | return 0; |
865 | } | 865 | } |
866 | 866 | ||
867 | void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu) | ||
868 | { | ||
869 | struct kvm_lapic *apic = vcpu->arch.apic; | ||
870 | |||
871 | if (apic) | ||
872 | apic_reg_write(vcpu->arch.apic, APIC_EOI, 0); | ||
873 | } | ||
874 | EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); | ||
875 | |||
867 | void kvm_free_lapic(struct kvm_vcpu *vcpu) | 876 | void kvm_free_lapic(struct kvm_vcpu *vcpu) |
868 | { | 877 | { |
869 | if (!vcpu->arch.apic) | 878 | if (!vcpu->arch.apic) |
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 52c9e6b9e725..82872432d475 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h | |||
@@ -26,6 +26,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu); | |||
26 | void kvm_lapic_reset(struct kvm_vcpu *vcpu); | 26 | void kvm_lapic_reset(struct kvm_vcpu *vcpu); |
27 | u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); | 27 | u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); |
28 | void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); | 28 | void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); |
29 | void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu); | ||
29 | void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); | 30 | void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); |
30 | u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); | 31 | u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); |
31 | void kvm_apic_set_version(struct kvm_vcpu *vcpu); | 32 | void kvm_apic_set_version(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 5e8d411b0a81..47419d6031ea 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -71,6 +71,9 @@ module_param(vmm_exclusive, bool, S_IRUGO); | |||
71 | static int __read_mostly yield_on_hlt = 1; | 71 | static int __read_mostly yield_on_hlt = 1; |
72 | module_param(yield_on_hlt, bool, S_IRUGO); | 72 | module_param(yield_on_hlt, bool, S_IRUGO); |
73 | 73 | ||
74 | static int __read_mostly fasteoi = 1; | ||
75 | module_param(fasteoi, bool, S_IRUGO); | ||
76 | |||
74 | /* | 77 | /* |
75 | * If nested=1, nested virtualization is supported, i.e., guests may use | 78 | * If nested=1, nested virtualization is supported, i.e., guests may use |
76 | * VMX and be a hypervisor for its own guests. If nested=0, guests may not | 79 | * VMX and be a hypervisor for its own guests. If nested=0, guests may not |
@@ -4540,6 +4543,24 @@ static int handle_xsetbv(struct kvm_vcpu *vcpu) | |||
4540 | 4543 | ||
4541 | static int handle_apic_access(struct kvm_vcpu *vcpu) | 4544 | static int handle_apic_access(struct kvm_vcpu *vcpu) |
4542 | { | 4545 | { |
4546 | if (likely(fasteoi)) { | ||
4547 | unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); | ||
4548 | int access_type, offset; | ||
4549 | |||
4550 | access_type = exit_qualification & APIC_ACCESS_TYPE; | ||
4551 | offset = exit_qualification & APIC_ACCESS_OFFSET; | ||
4552 | /* | ||
4553 | * Sane guest uses MOV to write EOI, with written value | ||
4554 | * not cared. So make a short-circuit here by avoiding | ||
4555 | * heavy instruction emulation. | ||
4556 | */ | ||
4557 | if ((access_type == TYPE_LINEAR_APIC_INST_WRITE) && | ||
4558 | (offset == APIC_EOI)) { | ||
4559 | kvm_lapic_set_eoi(vcpu); | ||
4560 | skip_emulated_instruction(vcpu); | ||
4561 | return 1; | ||
4562 | } | ||
4563 | } | ||
4543 | return emulate_instruction(vcpu, 0) == EMULATE_DONE; | 4564 | return emulate_instruction(vcpu, 0) == EMULATE_DONE; |
4544 | } | 4565 | } |
4545 | 4566 | ||