aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Tian <kevin.tian@intel.com>2011-08-30 06:56:17 -0400
committerAvi Kivity <avi@redhat.com>2011-09-25 12:52:17 -0400
commit58fbbf26eb01cf6d92cf18da8d14b3a4af9c4b47 (patch)
tree738874a15a233eed6e2e18d9cfe99f09482e8b17
parent45133ecaaec7aea447afc98cc2c24aac638bbe5c (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.h12
-rw-r--r--arch/x86/kvm/lapic.c9
-rw-r--r--arch/x86/kvm/lapic.h1
-rw-r--r--arch/x86/kvm/vmx.c21
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
867void 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}
874EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
875
867void kvm_free_lapic(struct kvm_vcpu *vcpu) 876void 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);
26void kvm_lapic_reset(struct kvm_vcpu *vcpu); 26void kvm_lapic_reset(struct kvm_vcpu *vcpu);
27u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); 27u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
28void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); 28void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
29void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
29void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); 30void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
30u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); 31u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
31void kvm_apic_set_version(struct kvm_vcpu *vcpu); 32void 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);
71static int __read_mostly yield_on_hlt = 1; 71static int __read_mostly yield_on_hlt = 1;
72module_param(yield_on_hlt, bool, S_IRUGO); 72module_param(yield_on_hlt, bool, S_IRUGO);
73 73
74static int __read_mostly fasteoi = 1;
75module_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
4541static int handle_apic_access(struct kvm_vcpu *vcpu) 4544static 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