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>
This commit is contained in:
parent
45133ecaae
commit
58fbbf26eb
|
@ -350,6 +350,18 @@ enum vmcs_field {
|
||||||
#define DEBUG_REG_ACCESS_REG(eq) (((eq) >> 8) & 0xf) /* 11:8, general purpose reg. */
|
#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 */
|
/* segment AR */
|
||||||
#define SEGMENT_AR_L_MASK (1 << 13)
|
#define SEGMENT_AR_L_MASK (1 << 13)
|
||||||
|
|
||||||
|
|
|
@ -864,6 +864,15 @@ static int apic_mmio_write(struct kvm_io_device *this,
|
||||||
return 0;
|
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)
|
void kvm_free_lapic(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
if (!vcpu->arch.apic)
|
if (!vcpu->arch.apic)
|
||||||
|
|
|
@ -26,6 +26,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
|
||||||
void kvm_lapic_reset(struct kvm_vcpu *vcpu);
|
void kvm_lapic_reset(struct kvm_vcpu *vcpu);
|
||||||
u64 kvm_lapic_get_cr8(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_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);
|
void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
|
||||||
u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
|
u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
|
||||||
void kvm_apic_set_version(struct kvm_vcpu *vcpu);
|
void kvm_apic_set_version(struct kvm_vcpu *vcpu);
|
||||||
|
|
|
@ -71,6 +71,9 @@ module_param(vmm_exclusive, bool, S_IRUGO);
|
||||||
static int __read_mostly yield_on_hlt = 1;
|
static int __read_mostly yield_on_hlt = 1;
|
||||||
module_param(yield_on_hlt, bool, S_IRUGO);
|
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
|
* 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
|
* 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)
|
||||||
|
|
||||||
static int handle_apic_access(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;
|
return emulate_instruction(vcpu, 0) == EMULATE_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue