Skip to content

Commit

Permalink
KVM: APIC: avoid instruction emulation for EOI writes
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kevin Tian authored and Avi Kivity committed Sep 25, 2011
1 parent 45133ec commit 58fbbf2
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 0 deletions.
12 changes: 12 additions & 0 deletions arch/x86/include/asm/vmx.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,18 @@ enum vmcs_field {
#define DEBUG_REG_ACCESS_REG(eq) (((eq) >> 8) & 0xf) /* 11:8, general purpose reg. */


/*
* Exit Qualifications for APIC-Access
*/
#define APIC_ACCESS_OFFSET 0xfff /* 11:0, offset within the APIC page */
#define APIC_ACCESS_TYPE 0xf000 /* 15:12, access type */
#define TYPE_LINEAR_APIC_INST_READ (0 << 12)
#define TYPE_LINEAR_APIC_INST_WRITE (1 << 12)
#define TYPE_LINEAR_APIC_INST_FETCH (2 << 12)
#define TYPE_LINEAR_APIC_EVENT (3 << 12)
#define TYPE_PHYSICAL_APIC_EVENT (10 << 12)
#define TYPE_PHYSICAL_APIC_INST (15 << 12)

/* segment AR */
#define SEGMENT_AR_L_MASK (1 << 13)

Expand Down
9 changes: 9 additions & 0 deletions arch/x86/kvm/lapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,15 @@ static int apic_mmio_write(struct kvm_io_device *this,
return 0;
}

void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;

if (apic)
apic_reg_write(vcpu->arch.apic, APIC_EOI, 0);
}
EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);

void kvm_free_lapic(struct kvm_vcpu *vcpu)
{
if (!vcpu->arch.apic)
Expand Down
1 change: 1 addition & 0 deletions arch/x86/kvm/lapic.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
void kvm_lapic_reset(struct kvm_vcpu *vcpu);
u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
void kvm_apic_set_version(struct kvm_vcpu *vcpu);
Expand Down
21 changes: 21 additions & 0 deletions arch/x86/kvm/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ module_param(vmm_exclusive, bool, S_IRUGO);
static int __read_mostly yield_on_hlt = 1;
module_param(yield_on_hlt, bool, S_IRUGO);

static int __read_mostly fasteoi = 1;
module_param(fasteoi, bool, S_IRUGO);

/*
* If nested=1, nested virtualization is supported, i.e., guests may use
* VMX and be a hypervisor for its own guests. If nested=0, guests may not
Expand Down Expand Up @@ -4540,6 +4543,24 @@ static int handle_xsetbv(struct kvm_vcpu *vcpu)

static int handle_apic_access(struct kvm_vcpu *vcpu)
{
if (likely(fasteoi)) {
unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
int access_type, offset;

access_type = exit_qualification & APIC_ACCESS_TYPE;
offset = exit_qualification & APIC_ACCESS_OFFSET;
/*
* Sane guest uses MOV to write EOI, with written value
* not cared. So make a short-circuit here by avoiding
* heavy instruction emulation.
*/
if ((access_type == TYPE_LINEAR_APIC_INST_WRITE) &&
(offset == APIC_EOI)) {
kvm_lapic_set_eoi(vcpu);
skip_emulated_instruction(vcpu);
return 1;
}
}
return emulate_instruction(vcpu, 0) == EMULATE_DONE;
}

Expand Down

0 comments on commit 58fbbf2

Please sign in to comment.