Commit dff7ec18 authored by Andrey Smetanin's avatar Andrey Smetanin Committed by Kamal Mostafa

kvm/x86: per-vcpu apicv deactivation support

BugLink: http://bugs.launchpad.net/bugs/1583357

The decision on whether to use hardware APIC virtualization used to be
taken globally, based on the availability of the feature in the CPU
and the value of a module parameter.

However, under certain circumstances we want to control it on per-vcpu
basis.  In particular, when the userspace activates HyperV synthetic
interrupt controller (SynIC), APICv has to be disabled as it's
incompatible with SynIC auto-EOI behavior.

To achieve that, introduce 'apicv_active' flag on struct
kvm_vcpu_arch, and kvm_vcpu_deactivate_apicv() function to turn APICv
off.  The flag is initialized based on the module parameter and CPU
capability, and consulted whenever an APICv-specific action is
performed.
Signed-off-by: default avatarAndrey Smetanin <asmetanin@virtuozzo.com>
Reviewed-by: default avatarRoman Kagan <rkagan@virtuozzo.com>
Signed-off-by: default avatarDenis V. Lunev <den@openvz.org>
CC: Gleb Natapov <gleb@kernel.org>
CC: Paolo Bonzini <pbonzini@redhat.com>
CC: Roman Kagan <rkagan@virtuozzo.com>
CC: Denis V. Lunev <den@openvz.org>
CC: qemu-devel@nongnu.org
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit d62caabb)
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
Acked-by: default avatarBrad Figg <brad.figg@canonical.com>
Signed-off-by: default avatarKamal Mostafa <kamal@canonical.com>
parent 63e1d15e
...@@ -400,6 +400,7 @@ struct kvm_vcpu_arch { ...@@ -400,6 +400,7 @@ struct kvm_vcpu_arch {
u64 efer; u64 efer;
u64 apic_base; u64 apic_base;
struct kvm_lapic *apic; /* kernel irqchip context */ struct kvm_lapic *apic; /* kernel irqchip context */
bool apicv_active;
DECLARE_BITMAP(ioapic_handled_vectors, 256); DECLARE_BITMAP(ioapic_handled_vectors, 256);
unsigned long apic_attention; unsigned long apic_attention;
int32_t apic_arb_prio; int32_t apic_arb_prio;
...@@ -831,7 +832,8 @@ struct kvm_x86_ops { ...@@ -831,7 +832,8 @@ struct kvm_x86_ops {
void (*enable_nmi_window)(struct kvm_vcpu *vcpu); void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
void (*enable_irq_window)(struct kvm_vcpu *vcpu); void (*enable_irq_window)(struct kvm_vcpu *vcpu);
void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
int (*cpu_uses_apicv)(struct kvm_vcpu *vcpu); bool (*get_enable_apicv)(void);
void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
void (*hwapic_isr_update)(struct kvm *kvm, int isr); void (*hwapic_isr_update)(struct kvm *kvm, int isr);
void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
...@@ -1086,6 +1088,8 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, ...@@ -1086,6 +1088,8 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva,
gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
struct x86_exception *exception); struct x86_exception *exception);
void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu);
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code, int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code,
......
...@@ -76,7 +76,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v) ...@@ -76,7 +76,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
if (kvm_cpu_has_extint(v)) if (kvm_cpu_has_extint(v))
return 1; return 1;
if (kvm_vcpu_apic_vid_enabled(v)) if (kvm_vcpu_apicv_active(v))
return 0; return 0;
return kvm_apic_has_interrupt(v) != -1; /* LAPIC */ return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
......
...@@ -379,6 +379,7 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic) ...@@ -379,6 +379,7 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)
if (!apic->irr_pending) if (!apic->irr_pending)
return -1; return -1;
if (apic->vcpu->arch.apicv_active)
kvm_x86_ops->sync_pir_to_irr(apic->vcpu); kvm_x86_ops->sync_pir_to_irr(apic->vcpu);
result = apic_search_irr(apic); result = apic_search_irr(apic);
ASSERT(result == -1 || result >= 16); ASSERT(result == -1 || result >= 16);
...@@ -392,7 +393,7 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) ...@@ -392,7 +393,7 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
vcpu = apic->vcpu; vcpu = apic->vcpu;
if (unlikely(kvm_vcpu_apic_vid_enabled(vcpu))) { if (unlikely(vcpu->arch.apicv_active)) {
/* try to update RVI */ /* try to update RVI */
apic_clear_vector(vec, apic->regs + APIC_IRR); apic_clear_vector(vec, apic->regs + APIC_IRR);
kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_make_request(KVM_REQ_EVENT, vcpu);
...@@ -418,7 +419,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic) ...@@ -418,7 +419,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
* because the processor can modify ISR under the hood. Instead * because the processor can modify ISR under the hood. Instead
* just set SVI. * just set SVI.
*/ */
if (unlikely(kvm_x86_ops->hwapic_isr_update)) if (unlikely(vcpu->arch.apicv_active))
kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec); kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec);
else { else {
++apic->isr_count; ++apic->isr_count;
...@@ -466,7 +467,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) ...@@ -466,7 +467,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
* on the other hand isr_count and highest_isr_cache are unused * on the other hand isr_count and highest_isr_cache are unused
* and must be left alone. * and must be left alone.
*/ */
if (unlikely(kvm_x86_ops->hwapic_isr_update)) if (unlikely(vcpu->arch.apicv_active))
kvm_x86_ops->hwapic_isr_update(vcpu->kvm, kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
apic_find_highest_isr(apic)); apic_find_highest_isr(apic));
else { else {
...@@ -852,7 +853,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, ...@@ -852,7 +853,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
apic_clear_vector(vector, apic->regs + APIC_TMR); apic_clear_vector(vector, apic->regs + APIC_TMR);
} }
if (kvm_x86_ops->deliver_posted_interrupt) if (vcpu->arch.apicv_active)
kvm_x86_ops->deliver_posted_interrupt(vcpu, vector); kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
else { else {
apic_set_irr(vector, apic); apic_set_irr(vector, apic);
...@@ -1225,7 +1226,7 @@ static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu) ...@@ -1225,7 +1226,7 @@ static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu)
int vec = reg & APIC_VECTOR_MASK; int vec = reg & APIC_VECTOR_MASK;
void *bitmap = apic->regs + APIC_ISR; void *bitmap = apic->regs + APIC_ISR;
if (kvm_x86_ops->deliver_posted_interrupt) if (vcpu->arch.apicv_active)
bitmap = apic->regs + APIC_IRR; bitmap = apic->regs + APIC_IRR;
if (apic_test_vector(vec, bitmap)) if (apic_test_vector(vec, bitmap))
...@@ -1693,8 +1694,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) ...@@ -1693,8 +1694,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
} }
apic->irr_pending = kvm_vcpu_apic_vid_enabled(vcpu); apic->irr_pending = vcpu->arch.apicv_active;
apic->isr_count = kvm_x86_ops->hwapic_isr_update ? 1 : 0; apic->isr_count = vcpu->arch.apicv_active ? 1 : 0;
apic->highest_isr_cache = -1; apic->highest_isr_cache = -1;
update_divide_count(apic); update_divide_count(apic);
atomic_set(&apic->lapic_timer.pending, 0); atomic_set(&apic->lapic_timer.pending, 0);
...@@ -1906,15 +1907,15 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, ...@@ -1906,15 +1907,15 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
update_divide_count(apic); update_divide_count(apic);
start_apic_timer(apic); start_apic_timer(apic);
apic->irr_pending = true; apic->irr_pending = true;
apic->isr_count = kvm_x86_ops->hwapic_isr_update ? apic->isr_count = vcpu->arch.apicv_active ?
1 : count_vectors(apic->regs + APIC_ISR); 1 : count_vectors(apic->regs + APIC_ISR);
apic->highest_isr_cache = -1; apic->highest_isr_cache = -1;
if (kvm_x86_ops->hwapic_irr_update) if (vcpu->arch.apicv_active) {
kvm_x86_ops->hwapic_irr_update(vcpu, kvm_x86_ops->hwapic_irr_update(vcpu,
apic_find_highest_irr(apic)); apic_find_highest_irr(apic));
if (unlikely(kvm_x86_ops->hwapic_isr_update))
kvm_x86_ops->hwapic_isr_update(vcpu->kvm, kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
apic_find_highest_isr(apic)); apic_find_highest_isr(apic));
}
kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_make_request(KVM_REQ_EVENT, vcpu);
if (ioapic_in_kernel(vcpu->kvm)) if (ioapic_in_kernel(vcpu->kvm))
kvm_rtc_eoi_tracking_restore_one(vcpu); kvm_rtc_eoi_tracking_restore_one(vcpu);
......
...@@ -143,9 +143,9 @@ static inline int apic_x2apic_mode(struct kvm_lapic *apic) ...@@ -143,9 +143,9 @@ static inline int apic_x2apic_mode(struct kvm_lapic *apic)
return apic->vcpu->arch.apic_base & X2APIC_ENABLE; return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
} }
static inline bool kvm_vcpu_apic_vid_enabled(struct kvm_vcpu *vcpu) static inline bool kvm_vcpu_apicv_active(struct kvm_vcpu *vcpu)
{ {
return kvm_x86_ops->cpu_uses_apicv(vcpu); return vcpu->arch.apic && vcpu->arch.apicv_active;
} }
static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu) static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu)
......
...@@ -3561,9 +3561,13 @@ static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set) ...@@ -3561,9 +3561,13 @@ static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
return; return;
} }
static int svm_cpu_uses_apicv(struct kvm_vcpu *vcpu) static bool svm_get_enable_apicv(void)
{
return false;
}
static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
{ {
return 0;
} }
static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
...@@ -4328,7 +4332,8 @@ static struct kvm_x86_ops svm_x86_ops = { ...@@ -4328,7 +4332,8 @@ static struct kvm_x86_ops svm_x86_ops = {
.enable_irq_window = enable_irq_window, .enable_irq_window = enable_irq_window,
.update_cr8_intercept = update_cr8_intercept, .update_cr8_intercept = update_cr8_intercept,
.set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode, .set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
.cpu_uses_apicv = svm_cpu_uses_apicv, .get_enable_apicv = svm_get_enable_apicv,
.refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl,
.load_eoi_exitmap = svm_load_eoi_exitmap, .load_eoi_exitmap = svm_load_eoi_exitmap,
.sync_pir_to_irr = svm_sync_pir_to_irr, .sync_pir_to_irr = svm_sync_pir_to_irr,
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "irq.h" #include "irq.h"
#include "mmu.h" #include "mmu.h"
#include "cpuid.h" #include "cpuid.h"
#include "lapic.h"
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -864,7 +865,6 @@ static void kvm_cpu_vmxon(u64 addr); ...@@ -864,7 +865,6 @@ static void kvm_cpu_vmxon(u64 addr);
static void kvm_cpu_vmxoff(void); static void kvm_cpu_vmxoff(void);
static bool vmx_mpx_supported(void); static bool vmx_mpx_supported(void);
static bool vmx_xsaves_supported(void); static bool vmx_xsaves_supported(void);
static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu);
static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr); static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
static void vmx_set_segment(struct kvm_vcpu *vcpu, static void vmx_set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg); struct kvm_segment *var, int seg);
...@@ -872,7 +872,6 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu, ...@@ -872,7 +872,6 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg); struct kvm_segment *var, int seg);
static bool guest_state_valid(struct kvm_vcpu *vcpu); static bool guest_state_valid(struct kvm_vcpu *vcpu);
static u32 vmx_segment_access_rights(struct kvm_segment *var); static u32 vmx_segment_access_rights(struct kvm_segment *var);
static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu);
static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx); static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx);
static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx); static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx);
static int alloc_identity_pagetable(struct kvm *kvm); static int alloc_identity_pagetable(struct kvm *kvm);
...@@ -2519,7 +2518,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx) ...@@ -2519,7 +2518,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
vmx->nested.nested_vmx_pinbased_ctls_high |= vmx->nested.nested_vmx_pinbased_ctls_high |=
PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
PIN_BASED_VMX_PREEMPTION_TIMER; PIN_BASED_VMX_PREEMPTION_TIMER;
if (vmx_cpu_uses_apicv(&vmx->vcpu)) if (kvm_vcpu_apicv_active(&vmx->vcpu))
vmx->nested.nested_vmx_pinbased_ctls_high |= vmx->nested.nested_vmx_pinbased_ctls_high |=
PIN_BASED_POSTED_INTR; PIN_BASED_POSTED_INTR;
...@@ -4490,9 +4489,9 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr) ...@@ -4490,9 +4489,9 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
msr, MSR_TYPE_W); msr, MSR_TYPE_W);
} }
static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu) static bool vmx_get_enable_apicv(void)
{ {
return enable_apicv && lapic_in_kernel(vcpu); return enable_apicv;
} }
static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu) static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
...@@ -4614,11 +4613,6 @@ static void vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu) ...@@ -4614,11 +4613,6 @@ static void vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
kvm_apic_update_irr(vcpu, vmx->pi_desc.pir); kvm_apic_update_irr(vcpu, vmx->pi_desc.pir);
} }
static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu)
{
return;
}
/* /*
* Set up the vmcs's constant host-state fields, i.e., host-state fields that * Set up the vmcs's constant host-state fields, i.e., host-state fields that
* will not change in the lifetime of the guest. * will not change in the lifetime of the guest.
...@@ -4688,11 +4682,18 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx) ...@@ -4688,11 +4682,18 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
{ {
u32 pin_based_exec_ctrl = vmcs_config.pin_based_exec_ctrl; u32 pin_based_exec_ctrl = vmcs_config.pin_based_exec_ctrl;
if (!vmx_cpu_uses_apicv(&vmx->vcpu)) if (!kvm_vcpu_apicv_active(&vmx->vcpu))
pin_based_exec_ctrl &= ~PIN_BASED_POSTED_INTR; pin_based_exec_ctrl &= ~PIN_BASED_POSTED_INTR;
return pin_based_exec_ctrl; return pin_based_exec_ctrl;
} }
static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
}
static u32 vmx_exec_control(struct vcpu_vmx *vmx) static u32 vmx_exec_control(struct vcpu_vmx *vmx)
{ {
u32 exec_control = vmcs_config.cpu_based_exec_ctrl; u32 exec_control = vmcs_config.cpu_based_exec_ctrl;
...@@ -4731,7 +4732,7 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx) ...@@ -4731,7 +4732,7 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx)
exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST; exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
if (!ple_gap) if (!ple_gap)
exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING; exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING;
if (!vmx_cpu_uses_apicv(&vmx->vcpu)) if (!kvm_vcpu_apicv_active(&vmx->vcpu))
exec_control &= ~(SECONDARY_EXEC_APIC_REGISTER_VIRT | exec_control &= ~(SECONDARY_EXEC_APIC_REGISTER_VIRT |
SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE; exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
...@@ -4795,7 +4796,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) ...@@ -4795,7 +4796,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_write32(SECONDARY_VM_EXEC_CONTROL, vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
vmx_secondary_exec_control(vmx)); vmx_secondary_exec_control(vmx));
if (vmx_cpu_uses_apicv(&vmx->vcpu)) { if (kvm_vcpu_apicv_active(&vmx->vcpu)) {
vmcs_write64(EOI_EXIT_BITMAP0, 0); vmcs_write64(EOI_EXIT_BITMAP0, 0);
vmcs_write64(EOI_EXIT_BITMAP1, 0); vmcs_write64(EOI_EXIT_BITMAP1, 0);
vmcs_write64(EOI_EXIT_BITMAP2, 0); vmcs_write64(EOI_EXIT_BITMAP2, 0);
...@@ -4947,7 +4948,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) ...@@ -4947,7 +4948,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu); kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
if (vmx_cpu_uses_apicv(vcpu)) if (kvm_vcpu_apicv_active(vcpu))
memset(&vmx->pi_desc, 0, sizeof(struct pi_desc)); memset(&vmx->pi_desc, 0, sizeof(struct pi_desc));
if (vmx->vpid != 0) if (vmx->vpid != 0)
...@@ -6231,15 +6232,6 @@ static __init int hardware_setup(void) ...@@ -6231,15 +6232,6 @@ static __init int hardware_setup(void)
kvm_tsc_scaling_ratio_frac_bits = 48; kvm_tsc_scaling_ratio_frac_bits = 48;
} }
if (enable_apicv)
kvm_x86_ops->update_cr8_intercept = NULL;
else {
kvm_x86_ops->hwapic_irr_update = NULL;
kvm_x86_ops->hwapic_isr_update = NULL;
kvm_x86_ops->deliver_posted_interrupt = NULL;
kvm_x86_ops->sync_pir_to_irr = vmx_sync_pir_to_irr_dummy;
}
vmx_disable_intercept_for_msr(MSR_FS_BASE, false); vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
vmx_disable_intercept_for_msr(MSR_GS_BASE, false); vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true); vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
...@@ -8189,7 +8181,7 @@ static void vmx_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set) ...@@ -8189,7 +8181,7 @@ static void vmx_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
* apicv * apicv
*/ */
if (!cpu_has_vmx_virtualize_x2apic_mode() || if (!cpu_has_vmx_virtualize_x2apic_mode() ||
!vmx_cpu_uses_apicv(vcpu)) !kvm_vcpu_apicv_active(vcpu))
return; return;
if (!cpu_need_tpr_shadow(vcpu)) if (!cpu_need_tpr_shadow(vcpu))
...@@ -8296,7 +8288,7 @@ static void vmx_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr) ...@@ -8296,7 +8288,7 @@ static void vmx_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap) static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
{ {
if (!vmx_cpu_uses_apicv(vcpu)) if (!kvm_vcpu_apicv_active(vcpu))
return; return;
vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]); vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
...@@ -10840,7 +10832,8 @@ static struct kvm_x86_ops vmx_x86_ops = { ...@@ -10840,7 +10832,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
.update_cr8_intercept = update_cr8_intercept, .update_cr8_intercept = update_cr8_intercept,
.set_virtual_x2apic_mode = vmx_set_virtual_x2apic_mode, .set_virtual_x2apic_mode = vmx_set_virtual_x2apic_mode,
.set_apic_access_page_addr = vmx_set_apic_access_page_addr, .set_apic_access_page_addr = vmx_set_apic_access_page_addr,
.cpu_uses_apicv = vmx_cpu_uses_apicv, .get_enable_apicv = vmx_get_enable_apicv,
.refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
.load_eoi_exitmap = vmx_load_eoi_exitmap, .load_eoi_exitmap = vmx_load_eoi_exitmap,
.hwapic_irr_update = vmx_hwapic_irr_update, .hwapic_irr_update = vmx_hwapic_irr_update,
.hwapic_isr_update = vmx_hwapic_isr_update, .hwapic_isr_update = vmx_hwapic_isr_update,
......
...@@ -2747,7 +2747,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) ...@@ -2747,7 +2747,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
struct kvm_lapic_state *s) struct kvm_lapic_state *s)
{ {
if (vcpu->arch.apicv_active)
kvm_x86_ops->sync_pir_to_irr(vcpu); kvm_x86_ops->sync_pir_to_irr(vcpu);
memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s); memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s);
return 0; return 0;
...@@ -5872,6 +5874,12 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid) ...@@ -5872,6 +5874,12 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL); kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
} }
void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
{
vcpu->arch.apicv_active = false;
kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
}
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu) int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
{ {
unsigned long nr, a0, a1, a2, a3, ret; unsigned long nr, a0, a1, a2, a3, ret;
...@@ -5965,6 +5973,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu) ...@@ -5965,6 +5973,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
if (!vcpu->arch.apic) if (!vcpu->arch.apic)
return; return;
if (vcpu->arch.apicv_active)
return;
if (!vcpu->arch.apic->vapic_addr) if (!vcpu->arch.apic->vapic_addr)
max_irr = kvm_lapic_find_highest_irr(vcpu); max_irr = kvm_lapic_find_highest_irr(vcpu);
else else
...@@ -6309,6 +6320,7 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) ...@@ -6309,6 +6320,7 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
if (irqchip_split(vcpu->kvm)) if (irqchip_split(vcpu->kvm))
kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors); kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors);
else { else {
if (vcpu->arch.apicv_active)
kvm_x86_ops->sync_pir_to_irr(vcpu); kvm_x86_ops->sync_pir_to_irr(vcpu);
kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors); kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
} }
...@@ -6456,7 +6468,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) ...@@ -6456,7 +6468,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
* Update architecture specific hints for APIC * Update architecture specific hints for APIC
* virtual interrupt delivery. * virtual interrupt delivery.
*/ */
if (kvm_x86_ops->hwapic_irr_update) if (vcpu->arch.apicv_active)
kvm_x86_ops->hwapic_irr_update(vcpu, kvm_x86_ops->hwapic_irr_update(vcpu,
kvm_lapic_find_highest_irr(vcpu)); kvm_lapic_find_highest_irr(vcpu));
} }
...@@ -7528,6 +7540,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) ...@@ -7528,6 +7540,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
BUG_ON(vcpu->kvm == NULL); BUG_ON(vcpu->kvm == NULL);
kvm = vcpu->kvm; kvm = vcpu->kvm;
vcpu->arch.apicv_active = kvm_x86_ops->get_enable_apicv();
vcpu->arch.pv.pv_unhalted = false; vcpu->arch.pv.pv_unhalted = false;
vcpu->arch.emulate_ctxt.ops = &emulate_ops; vcpu->arch.emulate_ctxt.ops = &emulate_ops;
if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu)) if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment