Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
- index 329d01c689b7..4dffbc10d3f8 100644
- --- a/arch/x86/include/asm/kvm_host.h
- +++ b/arch/x86/include/asm/kvm_host.h
- @@ -78,6 +78,8 @@
- #define KVM_REQ_HV_STIMER KVM_ARCH_REQ(22)
- #define KVM_REQ_LOAD_EOI_EXITMAP KVM_ARCH_REQ(23)
- #define KVM_REQ_GET_VMCS12_PAGES KVM_ARCH_REQ(24)
- +#define KVM_REQ_APICV_UPDATE \
- + KVM_ARCH_REQ_FLAGS(25, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
- #define CR0_RESERVED_BITS \
- (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
- @@ -873,6 +875,12 @@ enum kvm_irqchip_mode {
- KVM_IRQCHIP_SPLIT, /* created with KVM_CAP_SPLIT_IRQCHIP */
- };
- +#define APICV_INHIBIT_REASON_DISABLE 0
- +#define APICV_INHIBIT_REASON_HYPERV 1
- +#define APICV_INHIBIT_REASON_NESTED 2
- +#define APICV_INHIBIT_REASON_IRQWIN 3
- +#define APICV_INHIBIT_REASON_PIT_REINJ 4
- +
- struct kvm_arch {
- unsigned long n_used_mmu_pages;
- unsigned long n_requested_mmu_pages;
- @@ -904,6 +912,7 @@ struct kvm_arch {
- struct kvm_apic_map *apic_map;
- bool apic_access_page_done;
- + unsigned long apicv_inhibit_reasons;
- gpa_t wall_clock;
- @@ -1118,7 +1127,8 @@ struct kvm_x86_ops {
- void (*enable_nmi_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);
- - bool (*get_enable_apicv)(struct kvm *kvm);
- + bool (*check_apicv_inhibit_reasons)(ulong bit);
- + void (*pre_update_apicv_exec_ctrl)(struct kvm *kvm, bool activate);
- void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
- void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
- void (*hwapic_isr_update)(struct kvm_vcpu *vcpu, int isr);
- @@ -1477,7 +1487,11 @@ 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,
- struct x86_exception *exception);
- -void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu);
- +bool kvm_apicv_activated(struct kvm *kvm);
- +void kvm_apicv_init(struct kvm *kvm, bool enable);
- +void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu);
- +void kvm_request_apicv_update(struct kvm *kvm, bool activate,
- + unsigned long bit);
- int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
- diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
- index 4df1c965bf1a..a86fda7a1d03 100644
- --- a/arch/x86/kvm/hyperv.c
- +++ b/arch/x86/kvm/hyperv.c
- @@ -776,9 +776,10 @@ int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages)
- /*
- * Hyper-V SynIC auto EOI SINT's are
- - * not compatible with APICV, so deactivate APICV
- + * not compatible with APICV, so request
- + * to deactivate APICV permanently.
- */
- - kvm_vcpu_deactivate_apicv(vcpu);
- + kvm_request_apicv_update(vcpu->kvm, false, APICV_INHIBIT_REASON_HYPERV);
- synic->active = true;
- synic->dont_zero_synic_pages = dont_zero_synic_pages;
- return 0;
- diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
- index 4a6dc54cc12b..b24c606ac04b 100644
- --- a/arch/x86/kvm/i8254.c
- +++ b/arch/x86/kvm/i8254.c
- @@ -295,12 +295,24 @@ void kvm_pit_set_reinject(struct kvm_pit *pit, bool reinject)
- if (atomic_read(&ps->reinject) == reinject)
- return;
- + /*
- + * AMD SVM AVIC accelerates EOI write and does not trap.
- + * This cause in-kernel PIT re-inject mode to fail
- + * since it checks ps->irq_ack before kvm_set_irq()
- + * and relies on the ack notifier to timely queue
- + * the pt->worker work iterm and reinject the missed tick.
- + * So, deactivate APICv when PIT is in reinject mode.
- + */
- if (reinject) {
- + kvm_request_apicv_update(kvm, false,
- + APICV_INHIBIT_REASON_PIT_REINJ);
- /* The initial state is preserved while ps->reinject == 0. */
- kvm_pit_reset_reinject(pit);
- kvm_register_irq_ack_notifier(kvm, &ps->irq_ack_notifier);
- kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
- } else {
- + kvm_request_apicv_update(kvm, true,
- + APICV_INHIBIT_REASON_PIT_REINJ);
- kvm_unregister_irq_ack_notifier(kvm, &ps->irq_ack_notifier);
- kvm_unregister_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
- }
- diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
- index 26aa22cb9b29..7668fed1ce65 100644
- --- a/arch/x86/kvm/ioapic.c
- +++ b/arch/x86/kvm/ioapic.c
- @@ -49,6 +49,11 @@
- static int ioapic_service(struct kvm_ioapic *vioapic, int irq,
- bool line_status);
- +static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,
- + struct kvm_ioapic *ioapic,
- + int trigger_mode,
- + int pin);
- +
- static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
- unsigned long addr,
- unsigned long length)
- @@ -154,10 +159,16 @@ static void kvm_rtc_eoi_tracking_restore_all(struct kvm_ioapic *ioapic)
- __rtc_irq_eoi_tracking_restore_one(vcpu);
- }
- -static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu)
- +static void rtc_irq_eoi(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu,
- + int vector)
- {
- - if (test_and_clear_bit(vcpu->vcpu_id,
- - ioapic->rtc_status.dest_map.map)) {
- + struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
- +
- + /* RTC special handling */
- + if (test_bit(vcpu->vcpu_id, dest_map->map) &&
- + (vector == dest_map->vectors[vcpu->vcpu_id]) &&
- + (test_and_clear_bit(vcpu->vcpu_id,
- + ioapic->rtc_status.dest_map.map))) {
- --ioapic->rtc_status.pending_eoi;
- rtc_status_pending_eoi_check_valid(ioapic);
- }
- @@ -171,6 +182,31 @@ static bool rtc_irq_check_coalesced(struct kvm_ioapic *ioapic)
- return false;
- }
- +static void ioapic_lazy_update_eoi(struct kvm_ioapic *ioapic, int irq)
- +{
- + int i;
- + struct kvm_vcpu *vcpu;
- + union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq];
- +
- + kvm_for_each_vcpu(i, vcpu, ioapic->kvm) {
- + if (!kvm_apic_match_dest(vcpu, NULL, APIC_DEST_NOSHORT,
- + entry->fields.dest_id,
- + entry->fields.dest_mode) ||
- + kvm_apic_pending_eoi(vcpu, entry->fields.vector))
- + continue;
- +
- + /*
- + * If no longer has pending EOI in LAPICs, update
- + * EOI for this vetor.
- + */
- + rtc_irq_eoi(ioapic, vcpu, entry->fields.vector);
- + kvm_ioapic_update_eoi_one(vcpu, ioapic,
- + entry->fields.trig_mode,
- + irq);
- + break;
- + }
- +}
- +
- static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
- int irq_level, bool line_status)
- {
- @@ -188,6 +224,15 @@ static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
- goto out;
- }
- + /*
- + * AMD SVM AVIC accelerate EOI write and do not trap,
- + * in-kernel IOAPIC will not be able to receive the EOI.
- + * In this case, we do lazy update of the pending EOI when
- + * trying to set IOAPIC irq.
- + */
- + if (kvm_apicv_activated(ioapic->kvm))
- + ioapic_lazy_update_eoi(ioapic, irq);
- +
- /*
- * Return 0 for coalesced interrupts; for edge-triggered interrupts,
- * this only happens if a previous edge has not been delivered due
- @@ -454,72 +499,68 @@ static void kvm_ioapic_eoi_inject_work(struct work_struct *work)
- }
- #define IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT 10000
- -
- -static void __kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu,
- - struct kvm_ioapic *ioapic, int vector, int trigger_mode)
- +static void kvm_ioapic_update_eoi_one(struct kvm_vcpu *vcpu,
- + struct kvm_ioapic *ioapic,
- + int trigger_mode,
- + int pin)
- {
- - struct dest_map *dest_map = &ioapic->rtc_status.dest_map;
- struct kvm_lapic *apic = vcpu->arch.apic;
- - int i;
- -
- - /* RTC special handling */
- - if (test_bit(vcpu->vcpu_id, dest_map->map) &&
- - vector == dest_map->vectors[vcpu->vcpu_id])
- - rtc_irq_eoi(ioapic, vcpu);
- -
- - for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- - union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
- -
- - if (ent->fields.vector != vector)
- - continue;
- + union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[pin];
- - /*
- - * We are dropping lock while calling ack notifiers because ack
- - * notifier callbacks for assigned devices call into IOAPIC
- - * recursively. Since remote_irr is cleared only after call
- - * to notifiers if the same vector will be delivered while lock
- - * is dropped it will be put into irr and will be delivered
- - * after ack notifier returns.
- - */
- - spin_unlock(&ioapic->lock);
- - kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, i);
- - spin_lock(&ioapic->lock);
- + /*
- + * We are dropping lock while calling ack notifiers because ack
- + * notifier callbacks for assigned devices call into IOAPIC
- + * recursively. Since remote_irr is cleared only after call
- + * to notifiers if the same vector will be delivered while lock
- + * is dropped it will be put into irr and will be delivered
- + * after ack notifier returns.
- + */
- + spin_unlock(&ioapic->lock);
- + kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin);
- + spin_lock(&ioapic->lock);
- - if (trigger_mode != IOAPIC_LEVEL_TRIG ||
- - kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
- - continue;
- + if (trigger_mode != IOAPIC_LEVEL_TRIG ||
- + kvm_lapic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)
- + return;
- - ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
- - ent->fields.remote_irr = 0;
- - if (!ent->fields.mask && (ioapic->irr & (1 << i))) {
- - ++ioapic->irq_eoi[i];
- - if (ioapic->irq_eoi[i] == IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT) {
- - /*
- - * Real hardware does not deliver the interrupt
- - * immediately during eoi broadcast, and this
- - * lets a buggy guest make slow progress
- - * even if it does not correctly handle a
- - * level-triggered interrupt. Emulate this
- - * behavior if we detect an interrupt storm.
- - */
- - schedule_delayed_work(&ioapic->eoi_inject, HZ / 100);
- - ioapic->irq_eoi[i] = 0;
- - trace_kvm_ioapic_delayed_eoi_inj(ent->bits);
- - } else {
- - ioapic_service(ioapic, i, false);
- - }
- + ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
- + ent->fields.remote_irr = 0;
- + if (!ent->fields.mask && (ioapic->irr & (1 << pin))) {
- + ++ioapic->irq_eoi[pin];
- + if (ioapic->irq_eoi[pin] == IOAPIC_SUCCESSIVE_IRQ_MAX_COUNT) {
- + /*
- + * Real hardware does not deliver the interrupt
- + * immediately during eoi broadcast, and this
- + * lets a buggy guest make slow progress
- + * even if it does not correctly handle a
- + * level-triggered interrupt. Emulate this
- + * behavior if we detect an interrupt storm.
- + */
- + schedule_delayed_work(&ioapic->eoi_inject, HZ / 100);
- + ioapic->irq_eoi[pin] = 0;
- + trace_kvm_ioapic_delayed_eoi_inj(ent->bits);
- } else {
- - ioapic->irq_eoi[i] = 0;
- + ioapic_service(ioapic, pin, false);
- }
- + } else {
- + ioapic->irq_eoi[pin] = 0;
- }
- }
- void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector, int trigger_mode)
- {
- + int i;
- struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
- spin_lock(&ioapic->lock);
- - __kvm_ioapic_update_eoi(vcpu, ioapic, vector, trigger_mode);
- + rtc_irq_eoi(ioapic, vcpu, vector);
- + for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- + union kvm_ioapic_redirect_entry *ent = &ioapic->redirtbl[i];
- +
- + if (ent->fields.vector != vector)
- + continue;
- + kvm_ioapic_update_eoi_one(vcpu, ioapic, trigger_mode, i);
- + }
- spin_unlock(&ioapic->lock);
- }
- diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
- index 9dbb990c319a..bf0556588ad0 100644
- --- a/arch/x86/kvm/svm.c
- +++ b/arch/x86/kvm/svm.c
- @@ -387,6 +387,8 @@ static u8 rsm_ins_bytes[] = "\x0f\xaa";
- static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
- static void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa);
- static void svm_complete_interrupts(struct vcpu_svm *svm);
- +static void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate);
- +static inline void avic_post_state_restore(struct kvm_vcpu *vcpu);
- static int nested_svm_exit_handled(struct vcpu_svm *svm);
- static int nested_svm_intercept(struct vcpu_svm *svm);
- @@ -1545,7 +1547,10 @@ static void avic_init_vmcb(struct vcpu_svm *svm)
- vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK;
- vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK;
- vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT;
- - vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
- + if (kvm_apicv_activated(svm->vcpu.kvm))
- + vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
- + else
- + vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
- }
- static void init_vmcb(struct vcpu_svm *svm)
- @@ -1729,23 +1734,28 @@ static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu,
- * field of the VMCB. Therefore, we set up the
- * APIC_ACCESS_PAGE_PRIVATE_MEMSLOT (4KB) here.
- */
- -static int avic_init_access_page(struct kvm_vcpu *vcpu)
- +static int avic_update_access_page(struct kvm *kvm, bool activate)
- {
- - struct kvm *kvm = vcpu->kvm;
- int ret = 0;
- mutex_lock(&kvm->slots_lock);
- - if (kvm->arch.apic_access_page_done)
- + /*
- + * During kvm_destroy_vm(), kvm_pit_set_reinject() could trigger
- + * APICv mode change, which update APIC_ACCESS_PAGE_PRIVATE_MEMSLOT
- + * memory region. So, we need to ensure that kvm->mm == current->mm.
- + */
- + if ((kvm->arch.apic_access_page_done == activate) ||
- + (kvm->mm != current->mm))
- goto out;
- ret = __x86_set_memory_region(kvm,
- APIC_ACCESS_PAGE_PRIVATE_MEMSLOT,
- APIC_DEFAULT_PHYS_BASE,
- - PAGE_SIZE);
- + activate ? PAGE_SIZE : 0);
- if (ret)
- goto out;
- - kvm->arch.apic_access_page_done = true;
- + kvm->arch.apic_access_page_done = activate;
- out:
- mutex_unlock(&kvm->slots_lock);
- return ret;
- @@ -1753,21 +1763,24 @@ static int avic_init_access_page(struct kvm_vcpu *vcpu)
- static int avic_init_backing_page(struct kvm_vcpu *vcpu)
- {
- - int ret;
- u64 *entry, new_entry;
- int id = vcpu->vcpu_id;
- struct vcpu_svm *svm = to_svm(vcpu);
- - ret = avic_init_access_page(vcpu);
- - if (ret)
- - return ret;
- -
- if (id >= AVIC_MAX_PHYSICAL_ID_COUNT)
- return -EINVAL;
- if (!svm->vcpu.arch.apic->regs)
- return -EINVAL;
- + if (kvm_apicv_activated(vcpu->kvm)) {
- + int ret;
- +
- + ret = avic_update_access_page(vcpu->kvm, true);
- + if (ret)
- + return ret;
- + }
- +
- svm->avic_backing_page = virt_to_page(svm->vcpu.arch.apic->regs);
- /* Setting AVIC backing page address in the phy APIC ID table */
- @@ -2052,6 +2065,18 @@ static int avic_vm_init(struct kvm *kvm)
- return err;
- }
- +static int svm_vm_init(struct kvm *kvm)
- +{
- + if (avic) {
- + int ret = avic_vm_init(kvm);
- + if (ret)
- + return ret;
- + }
- +
- + kvm_apicv_init(kvm, avic);
- + return 0;
- +}
- +
- static inline int
- avic_update_iommu_vcpu_affinity(struct kvm_vcpu *vcpu, int cpu, bool r)
- {
- @@ -2223,7 +2248,8 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
- /* We initialize this flag to true to make sure that the is_running
- * bit would be set the first time the vcpu is loaded.
- */
- - svm->avic_is_running = true;
- + if (irqchip_in_kernel(vcpu->kvm) && kvm_apicv_activated(vcpu->kvm))
- + svm->avic_is_running = true;
- svm->nested.hsave = page_address(hsave_page);
- @@ -2348,6 +2374,8 @@ static void svm_vcpu_blocking(struct kvm_vcpu *vcpu)
- static void svm_vcpu_unblocking(struct kvm_vcpu *vcpu)
- {
- + if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
- + kvm_vcpu_update_apicv(vcpu);
- avic_set_running(vcpu, true);
- }
- @@ -4440,6 +4468,14 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
- {
- kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
- svm_clear_vintr(svm);
- +
- + /*
- + * For AVIC, the only reason to end up here is ExtINTs.
- + * In this case AVIC was temporarily disabled for
- + * requesting the IRQ window and we have to re-enable it.
- + */
- + svm_toggle_avic_for_irq_window(&svm->vcpu, true);
- +
- svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
- mark_dirty(svm->vmcb, VMCB_INTR);
- ++svm->vcpu.stat.irq_window_exits;
- @@ -5135,30 +5171,79 @@ static void svm_set_virtual_apic_mode(struct kvm_vcpu *vcpu)
- return;
- }
- -static bool svm_get_enable_apicv(struct kvm *kvm)
- +static void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
- {
- - return avic && irqchip_split(kvm);
- }
- -static void svm_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
- +static void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr)
- {
- }
- -static void svm_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr)
- +static void svm_toggle_avic_for_irq_window(struct kvm_vcpu *vcpu, bool activate)
- {
- + if (!avic || !lapic_in_kernel(vcpu))
- + return;
- +
- + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
- + kvm_request_apicv_update(vcpu->kvm, activate,
- + APICV_INHIBIT_REASON_IRQWIN);
- + vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
- +}
- +
- +static int svm_set_pi_irte_mode(struct kvm_vcpu *vcpu, bool activate)
- +{
- + int ret = 0;
- + unsigned long flags;
- + struct amd_svm_iommu_ir *ir;
- + struct vcpu_svm *svm = to_svm(vcpu);
- +
- + if (!kvm_arch_has_assigned_device(vcpu->kvm))
- + return 0;
- +
- + /*
- + * Here, we go through the per-vcpu ir_list to update all existing
- + * interrupt remapping table entry targeting this vcpu.
- + */
- + spin_lock_irqsave(&svm->ir_list_lock, flags);
- +
- + if (list_empty(&svm->ir_list))
- + goto out;
- +
- + list_for_each_entry(ir, &svm->ir_list, node) {
- + if (activate)
- + ret = amd_iommu_activate_guest_mode(ir->data);
- + else
- + ret = amd_iommu_deactivate_guest_mode(ir->data);
- + if (ret)
- + break;
- + }
- +out:
- + spin_unlock_irqrestore(&svm->ir_list_lock, flags);
- + return ret;
- }
- -/* Note: Currently only used by Hyper-V. */
- static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
- {
- struct vcpu_svm *svm = to_svm(vcpu);
- struct vmcb *vmcb = svm->vmcb;
- + bool activated = kvm_vcpu_apicv_active(vcpu);
- - if (kvm_vcpu_apicv_active(vcpu))
- + if (activated) {
- + /**
- + * During AVIC temporary deactivation, guest could update
- + * APIC ID, DFR and LDR registers, which would not be trapped
- + * by avic_unaccelerated_access_interception(). In this case,
- + * we need to check and update the AVIC logical APIC ID table
- + * accordingly before re-activating.
- + */
- + avic_post_state_restore(vcpu);
- vmcb->control.int_ctl |= AVIC_ENABLE_MASK;
- - else
- + } else {
- vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK;
- + }
- mark_dirty(vmcb, VMCB_AVIC);
- +
- + svm_set_pi_irte_mode(vcpu, activated);
- }
- static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
- @@ -5445,9 +5530,6 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
- {
- struct vcpu_svm *svm = to_svm(vcpu);
- - if (kvm_vcpu_apicv_active(vcpu))
- - return;
- -
- /*
- * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
- * 1, because that's a separate STGI/VMRUN intercept. The next time we
- @@ -5457,6 +5539,13 @@ static void enable_irq_window(struct kvm_vcpu *vcpu)
- * window under the assumption that the hardware will set the GIF.
- */
- if ((vgif_enabled(svm) || gif_set(svm)) && nested_svm_intr(svm)) {
- + /*
- + * IRQ window is not needed when AVIC is enabled,
- + * unless we have pending ExtINT since it cannot be injected
- + * via AVIC. In such case, we need to temporarily disable AVIC,
- + * and fallback to injecting IRQ via V_IRQ.
- + */
- + svm_toggle_avic_for_irq_window(vcpu, false);
- svm_set_vintr(svm);
- svm_inject_irq(svm, 0x0);
- }
- @@ -5929,6 +6018,14 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu)
- return;
- guest_cpuid_clear(vcpu, X86_FEATURE_X2APIC);
- +
- + /*
- + * Currently, AVIC does not work with nested virtualization.
- + * So, we disable AVIC when cpuid for SVM is set in the L1 guest.
- + */
- + if (nested && guest_cpuid_has(vcpu, X86_FEATURE_SVM))
- + kvm_request_apicv_update(vcpu->kvm, false,
- + APICV_INHIBIT_REASON_NESTED);
- }
- #define F feature_bit
- @@ -7257,6 +7354,22 @@ static bool svm_apic_init_signal_blocked(struct kvm_vcpu *vcpu)
- (svm->vmcb->control.intercept & (1ULL << INTERCEPT_INIT));
- }
- +static bool svm_check_apicv_inhibit_reasons(ulong bit)
- +{
- + ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) |
- + BIT(APICV_INHIBIT_REASON_HYPERV) |
- + BIT(APICV_INHIBIT_REASON_NESTED) |
- + BIT(APICV_INHIBIT_REASON_IRQWIN) |
- + BIT(APICV_INHIBIT_REASON_PIT_REINJ);
- +
- + return supported & BIT(bit);
- +}
- +
- +static void svm_pre_update_apicv_exec_ctrl(struct kvm *kvm, bool activate)
- +{
- + avic_update_access_page(kvm, activate);
- +}
- +
- static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
- .cpu_has_kvm_support = has_svm,
- .disabled_by_bios = is_disabled,
- @@ -7274,7 +7387,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
- .vm_alloc = svm_vm_alloc,
- .vm_free = svm_vm_free,
- - .vm_init = avic_vm_init,
- + .vm_init = svm_vm_init,
- .vm_destroy = svm_vm_destroy,
- .prepare_guest_switch = svm_prepare_guest_switch,
- @@ -7331,8 +7444,9 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
- .enable_irq_window = enable_irq_window,
- .update_cr8_intercept = update_cr8_intercept,
- .set_virtual_apic_mode = svm_set_virtual_apic_mode,
- - .get_enable_apicv = svm_get_enable_apicv,
- .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl,
- + .check_apicv_inhibit_reasons = svm_check_apicv_inhibit_reasons,
- + .pre_update_apicv_exec_ctrl = svm_pre_update_apicv_exec_ctrl,
- .load_eoi_exitmap = svm_load_eoi_exitmap,
- .hwapic_irr_update = svm_hwapic_irr_update,
- .hwapic_isr_update = svm_hwapic_isr_update,
- diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
- index 7c741a0c5f80..f194dd058470 100644
- --- a/arch/x86/kvm/trace.h
- +++ b/arch/x86/kvm/trace.h
- @@ -1291,6 +1291,25 @@ TRACE_EVENT(kvm_hv_stimer_cleanup,
- __entry->vcpu_id, __entry->timer_index)
- );
- +TRACE_EVENT(kvm_apicv_update_request,
- + TP_PROTO(bool activate, unsigned long bit),
- + TP_ARGS(activate, bit),
- +
- + TP_STRUCT__entry(
- + __field(bool, activate)
- + __field(unsigned long, bit)
- + ),
- +
- + TP_fast_assign(
- + __entry->activate = activate;
- + __entry->bit = bit;
- + ),
- +
- + TP_printk("%s bit=%lu",
- + __entry->activate ? "activate" : "deactivate",
- + __entry->bit)
- +);
- +
- /*
- * Tracepoint for AMD AVIC
- */
- diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
- index c475fa2aaae0..678edbd6e278 100644
- --- a/arch/x86/kvm/vmx/vmx.c
- +++ b/arch/x86/kvm/vmx/vmx.c
- @@ -3719,11 +3719,6 @@ void pt_update_intercept_for_msr(struct vcpu_vmx *vmx)
- }
- }
- -static bool vmx_get_enable_apicv(struct kvm *kvm)
- -{
- - return enable_apicv;
- -}
- -
- static bool vmx_guest_apic_has_interrupt(struct kvm_vcpu *vcpu)
- {
- struct vcpu_vmx *vmx = to_vmx(vcpu);
- @@ -6813,6 +6808,7 @@ static int vmx_vm_init(struct kvm *kvm)
- break;
- }
- }
- + kvm_apicv_init(kvm, enable_apicv);
- return 0;
- }
- @@ -7714,6 +7710,14 @@ static __exit void hardware_unsetup(void)
- free_kvm_area();
- }
- +static bool vmx_check_apicv_inhibit_reasons(ulong bit)
- +{
- + ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) |
- + BIT(APICV_INHIBIT_REASON_HYPERV);
- +
- + return supported & BIT(bit);
- +}
- +
- static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
- .cpu_has_kvm_support = cpu_has_kvm_support,
- .disabled_by_bios = vmx_disabled_by_bios,
- @@ -7786,10 +7790,10 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
- .update_cr8_intercept = update_cr8_intercept,
- .set_virtual_apic_mode = vmx_set_virtual_apic_mode,
- .set_apic_access_page_addr = vmx_set_apic_access_page_addr,
- - .get_enable_apicv = vmx_get_enable_apicv,
- .refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
- .load_eoi_exitmap = vmx_load_eoi_exitmap,
- .apicv_post_state_restore = vmx_apicv_post_state_restore,
- + .check_apicv_inhibit_reasons = vmx_check_apicv_inhibit_reasons,
- .hwapic_irr_update = vmx_hwapic_irr_update,
- .hwapic_isr_update = vmx_hwapic_isr_update,
- .guest_apic_has_interrupt = vmx_guest_apic_has_interrupt,
- diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
- index 2d3be7f3ad67..52edf0bb46e5 100644
- --- a/arch/x86/kvm/x86.c
- +++ b/arch/x86/kvm/x86.c
- @@ -26,6 +26,7 @@
- #include "cpuid.h"
- #include "pmu.h"
- #include "hyperv.h"
- +#include "lapic.h"
- #include <linux/clocksource.h>
- #include <linux/interrupt.h>
- @@ -7456,18 +7457,22 @@ 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);
- }
- -void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
- +bool kvm_apicv_activated(struct kvm *kvm)
- {
- - if (!lapic_in_kernel(vcpu)) {
- - WARN_ON_ONCE(vcpu->arch.apicv_active);
- - return;
- - }
- - if (!vcpu->arch.apicv_active)
- - return;
- + return (READ_ONCE(kvm->arch.apicv_inhibit_reasons) == 0);
- +}
- +EXPORT_SYMBOL_GPL(kvm_apicv_activated);
- - vcpu->arch.apicv_active = false;
- - kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
- +void kvm_apicv_init(struct kvm *kvm, bool enable)
- +{
- + if (enable)
- + clear_bit(APICV_INHIBIT_REASON_DISABLE,
- + &kvm->arch.apicv_inhibit_reasons);
- + else
- + set_bit(APICV_INHIBIT_REASON_DISABLE,
- + &kvm->arch.apicv_inhibit_reasons);
- }
- +EXPORT_SYMBOL_GPL(kvm_apicv_init);
- static void kvm_sched_yield(struct kvm *kvm, unsigned long dest_id)
- {
- @@ -7996,6 +8001,47 @@ void kvm_make_scan_ioapic_request(struct kvm *kvm)
- kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
- }
- +void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu)
- +{
- + if (!lapic_in_kernel(vcpu))
- + return;
- +
- + vcpu->arch.apicv_active = kvm_apicv_activated(vcpu->kvm);
- + kvm_apic_update_apicv(vcpu);
- + kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
- +}
- +EXPORT_SYMBOL_GPL(kvm_vcpu_update_apicv);
- +
- +/*
- + * NOTE: Do not hold any lock prior to calling this.
- + *
- + * In particular, kvm_request_apicv_update() expects kvm->srcu not to be
- + * locked, because it calls __x86_set_memory_region() which does
- + * synchronize_srcu(&kvm->srcu).
- + */
- +void kvm_request_apicv_update(struct kvm *kvm, bool activate, ulong bit)
- +{
- + if (!kvm_x86_ops->check_apicv_inhibit_reasons ||
- + !kvm_x86_ops->check_apicv_inhibit_reasons(bit))
- + return;
- +
- + if (activate) {
- + if (!test_and_clear_bit(bit, &kvm->arch.apicv_inhibit_reasons) ||
- + !kvm_apicv_activated(kvm))
- + return;
- + } else {
- + if (test_and_set_bit(bit, &kvm->arch.apicv_inhibit_reasons) ||
- + kvm_apicv_activated(kvm))
- + return;
- + }
- +
- + trace_kvm_apicv_update_request(activate, bit);
- + if (kvm_x86_ops->pre_update_apicv_exec_ctrl)
- + kvm_x86_ops->pre_update_apicv_exec_ctrl(kvm, activate);
- + kvm_make_all_cpus_request(kvm, KVM_REQ_APICV_UPDATE);
- +}
- +EXPORT_SYMBOL_GPL(kvm_request_apicv_update);
- +
- static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
- {
- if (!kvm_apic_present(vcpu))
- @@ -8186,6 +8232,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
- */
- if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
- kvm_hv_process_stimers(vcpu);
- + if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu))
- + kvm_vcpu_update_apicv(vcpu);
- }
- if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
- @@ -9219,10 +9267,11 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
- return r;
- if (irqchip_in_kernel(vcpu->kvm)) {
- - vcpu->arch.apicv_active = kvm_x86_ops->get_enable_apicv(vcpu->kvm);
- r = kvm_create_lapic(vcpu, lapic_timer_advance_ns);
- if (r < 0)
- goto fail_mmu_destroy;
- + if (kvm_apicv_activated(vcpu->kvm))
- + vcpu->arch.apicv_active = true;
- } else
- static_key_slow_inc(&kvm_no_apic_vcpu);
- @@ -10448,3 +10497,4 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pml_full);
- EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pi_irte_update);
- EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_unaccelerated_access);
- EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_incomplete_ipi);
- +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_apicv_update_request);
- From patchwork Thu Mar 12 10:39:28 2020
- Content-Type: text/plain; charset="utf-8"
- MIME-Version: 1.0
- Content-Transfer-Encoding: 7bit
- X-Patchwork-Submitter: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
- X-Patchwork-Id: 1208775
- Return-Path: <SRS0=+FT0=45=vger.kernel.org=linux-kernel-owner@kernel.org>
- Received: from mail.kernel.org (mail.kernel.org [198.145.29.99])
- by smtp.lore.kernel.org (Postfix) with ESMTP id B1216C10DCE
- for <linux-kernel@archiver.kernel.org>; Thu, 12 Mar 2020 10:39:44 +0000 (UTC)
- Received: from vger.kernel.org (vger.kernel.org [209.132.180.67])
- by mail.kernel.org (Postfix) with ESMTP id 7C7A9206BE
- for <linux-kernel@archiver.kernel.org>; Thu, 12 Mar 2020 10:39:44 +0000 (UTC)
- Authentication-Results: mail.kernel.org;
- dkim=pass (1024-bit key) header.d=amdcloud.onmicrosoft.com
- header.i=@amdcloud.onmicrosoft.com header.b="ArIUjTS2"
- Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
- id S1726898AbgCLKjn (ORCPT
- <rfc822;linux-kernel@archiver.kernel.org>);
- Thu, 12 Mar 2020 06:39:43 -0400
- Received: from mail-dm6nam11on2042.outbound.protection.outlook.com
- ([40.107.223.42]:65504
- "EHLO NAM11-DM6-obe.outbound.protection.outlook.com"
- rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP
- id S1726023AbgCLKjm (ORCPT <rfc822;linux-kernel@vger.kernel.org>);
- Thu, 12 Mar 2020 06:39:42 -0400
- ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;
- b=cJ//0OxCNsTuWhvFb4ZnQgHAjrIFoINQgzVEBF93klN4rTvAU+m2yM+JwYFZTrNNy6bfyLgFt6Tb+GvXOh9IZaZZF+Yc2tCK6TyJMbkCWhBQaBAwXH0tpPp8mMkVor0AJ5YaQZVT9LLWqkL1yjuCrslzMSszPNz6/BesWhU5CEPELgd+iQmZa8b8pch8aAp3botQD2aIGeKt1DMDHXD2t0Izt7JHBOQ/HWk1yl0cfecnG1xTFDz638xebdYeeCdD1WGHqBTp4ethgEIvfILIs4INDmUrrHkjVMNUrzkJqDz5vaZTv4b5NEBLnvLBsHtwVGR+9IVhSC+1ndJDMuJ5tA==
- ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;
- s=arcselector9901;
- h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
- bh=fWlPjNv/NennGkA26zbaVAstC6MS7BJPLzel49z3I1c=;
- b=So1Bq24SCM9y7gTaltt8NCl7xLJD6BslokEMRk0CFhk1W1DmIdcTGLvgEuQaSvE7p5qQrvRjSiaV4JIvyzJKpyBfv+vrfmX6S1rJY4i0F60Hgy9PW6yZNxxmV58wwS+/sjxZecnM2lsox+5fYMC0auaXo9si4zS68qAcVdhCAGjwLlpdyqa6zZuRAp4B7jRMiaXHwnT/rKMKDzxTaHrUusj/8FAQyRYDptolqVLkqrAM3WPSNnVYJUOFSoa0VOn+LfvD6dwuZmBefukl+kl1HBB1QZhj/2DxLPtXa+lKtsrKq2/gqyPW4dhoFj46xETNyo6lH6X7Pwlz2hiCpTr7SA==
- ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass
- smtp.mailfrom=amd.com; dmarc=pass action=none header.from=amd.com; dkim=pass
- header.d=amd.com; arc=none
- DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
- d=amdcloud.onmicrosoft.com; s=selector2-amdcloud-onmicrosoft-com;
- h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;
- bh=fWlPjNv/NennGkA26zbaVAstC6MS7BJPLzel49z3I1c=;
- b=ArIUjTS2LZaV9MH7grOJemnrIWTIb4zMgTY4Qjckm0ek8xUo31didVQpsuMqi0tGVqFbwwRa0TBfPkOCJxgrCijlmb/CLML046k/m+uEh5FW2Sr6Pt5o4a82BQZGTYwULOCBH/1Vpfh8rMFABZ2PJMGZ0HWoeoccZv2ISuK3QQs=
- Authentication-Results: spf=none (sender IP is )
- smtp.mailfrom=Suravee.Suthikulpanit@amd.com;
- Received: from DM6PR12MB3865.namprd12.prod.outlook.com (2603:10b6:5:1c4::14)
- by DM6PR12MB2812.namprd12.prod.outlook.com (2603:10b6:5:44::27) with
- Microsoft SMTP Server (version=TLS1_2,
- cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2793.17; Thu, 12 Mar
- 2020 10:39:38 +0000
- Received: from DM6PR12MB3865.namprd12.prod.outlook.com
- ([fe80::2d84:ed9d:cba4:dcfd]) by DM6PR12MB3865.namprd12.prod.outlook.com
- ([fe80::2d84:ed9d:cba4:dcfd%3]) with mapi id 15.20.2793.018; Thu, 12 Mar 2020
- 10:39:37 +0000
- From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
- To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org
- Cc: pbonzini@redhat.com, joro@8bytes.org, jon.grimm@amd.com,
- Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
- Subject: [PATCH] kvm: svm: Introduce GA Log tracepoint for AVIC
- Date: Thu, 12 Mar 2020 05:39:28 -0500
- Message-Id: <1584009568-14089-1-git-send-email-suravee.suthikulpanit@amd.com>
- X-Mailer: git-send-email 1.8.3.1
- X-ClientProxiedBy: DM5PR2001CA0011.namprd20.prod.outlook.com
- (2603:10b6:4:16::21) To DM6PR12MB3865.namprd12.prod.outlook.com
- (2603:10b6:5:1c4::14)
- MIME-Version: 1.0
- X-MS-Exchange-MessageSentRepresentingType: 1
- Received: from ssuthiku-rhel7-ssp.amd.com (165.204.78.2) by
- DM5PR2001CA0011.namprd20.prod.outlook.com (2603:10b6:4:16::21) with Microsoft
- SMTP Server (version=TLS1_2,
- cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2793.16 via Frontend
- Transport; Thu, 12 Mar 2020 10:39:37 +0000
- X-Mailer: git-send-email 1.8.3.1
- X-Originating-IP: [165.204.78.2]
- X-MS-PublicTrafficType: Email
- X-MS-Office365-Filtering-HT: Tenant
- X-MS-Office365-Filtering-Correlation-Id: dcb947a3-853e-4140-a1a9-08d7c671a9a2
- X-MS-TrafficTypeDiagnostic: DM6PR12MB2812:|DM6PR12MB2812:
- X-MS-Exchange-Transport-Forked: True
- X-Microsoft-Antispam-PRVS:
- <DM6PR12MB28120BDE5B7890772626263EF3FD0@DM6PR12MB2812.namprd12.prod.outlook.com>
- X-MS-Oob-TLC-OOBClassifiers: OLM:4502;
- X-Forefront-PRVS: 0340850FCD
- X-Forefront-Antispam-Report:
- SFV:NSPM;SFS:(10009020)(4636009)(136003)(396003)(366004)(346002)(39860400002)(376002)(199004)(478600001)(4326008)(6666004)(86362001)(66556008)(66476007)(7696005)(316002)(81166006)(8676002)(81156014)(52116002)(2906002)(66946007)(5660300002)(6486002)(8936002)(16526019)(44832011)(956004)(2616005)(26005)(36756003)(186003);DIR:OUT;SFP:1101;SCL:1;SRVR:DM6PR12MB2812;H:DM6PR12MB3865.namprd12.prod.outlook.com;FPR:;SPF:None;LANG:en;PTR:InfoNoRecords;A:1;
- Received-SPF: None (protection.outlook.com: amd.com does not designate
- permitted sender hosts)
- X-MS-Exchange-SenderADCheck: 1
- X-Microsoft-Antispam: BCL:0;
- X-Microsoft-Antispam-Message-Info:
- FTBOzwS2IHHTpztPexVQk/N6ATf/++RSt7ztOUaIl6sPxfJgWytBYaqGm7alOHLD7E5KaIltnmdwE2jfR9yT6sbNF6HlTtnARVvc+cqS8RrxUaZGYfpXzhoZM6TtSAGcLnuk4x+u7W8QNvf7u8+do3DYpqC6SR3d8IR8t7vMlVbxmdcZrYF5QvnnwYDsSQZTCh8dZMvZ5JBX6gTvuZcx/KtwfYhBgMxUZO0PhHin6COHQHtv3/JbKFbnVRcAd1ng5T2qrHx+zuLz7dAPSr2WnGJealFA7QE9IoVWhMSTeYE1qWJIuTi/hKf5HTHlCcOzc8QQphIQQSQmsF5a423xUF35V5Cv05RbIx/KM2pcksAVrv0hay3MIu6Nc0PXAu8QEk61mpudCqME8UdkzynfarWMN4iQ3aay3OI0ZsSGXybETmiGypqsp2UHEK3Y39RP
- X-MS-Exchange-AntiSpam-MessageData:
- R8KUGQeKjOTa73q16Alk48bpW+D3xqx7EtqMUsvyjRv6aPqgVVhJkw6oKKWY16CWKtV1ULzy2OSFszfoVtEJZCQ/onXO2OWgsYKAWBGEXp6fmrMRuVIR51o0FEbed9R5gU/Lo5Kc2Ue2VJlnDbjxXA==
- X-OriginatorOrg: amd.com
- X-MS-Exchange-CrossTenant-Network-Message-Id:
- dcb947a3-853e-4140-a1a9-08d7c671a9a2
- X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Mar 2020 10:39:37.8294
- (UTC)
- X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted
- X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d
- X-MS-Exchange-CrossTenant-MailboxType: HOSTED
- X-MS-Exchange-CrossTenant-UserPrincipalName:
- 8T0Dfc4NvYJL51OpFfP7ab+zzKldgvJyD8rkl2NfAfqe7YqXud21D+COqcbQbx2+wS7nISYb8BKkSgXHqPlBtA==
- X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR12MB2812
- Sender: linux-kernel-owner@vger.kernel.org
- Precedence: bulk
- List-ID: <linux-kernel.vger.kernel.org>
- X-Mailing-List: linux-kernel@vger.kernel.org
- GA Log tracepoint is useful when debugging AVIC performance
- issue as it can be used with perf to count the number of times
- IOMMU AVIC injects interrupts through the slow-path instead of
- directly inject interrupts to the target vcpu.
- Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
- ---
- arch/x86/kvm/svm.c | 1 +
- arch/x86/kvm/trace.h | 18 ++++++++++++++++++
- arch/x86/kvm/x86.c | 1 +
- 3 files changed, 20 insertions(+)
- diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
- index 24c0b2b..504f2cb 100644
- --- a/arch/x86/kvm/svm.c
- +++ b/arch/x86/kvm/svm.c
- @@ -1208,6 +1208,7 @@ static int avic_ga_log_notifier(u32 ga_tag)
- u32 vcpu_id = AVIC_GATAG_TO_VCPUID(ga_tag);
- pr_debug("SVM: %s: vm_id=%#x, vcpu_id=%#x\n", __func__, vm_id, vcpu_id);
- + trace_kvm_avic_ga_log(vm_id, vcpu_id);
- spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
- hash_for_each_possible(svm_vm_data_hash, kvm_svm, hnode, vm_id) {
- diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
- index f194dd0..023de6c 100644
- --- a/arch/x86/kvm/trace.h
- +++ b/arch/x86/kvm/trace.h
- @@ -1367,6 +1367,24 @@
- __entry->vec)
- );
- +TRACE_EVENT(kvm_avic_ga_log,
- + TP_PROTO(u32 vmid, u32 vcpuid),
- + TP_ARGS(vmid, vcpuid),
- +
- + TP_STRUCT__entry(
- + __field(u32, vmid)
- + __field(u32, vcpuid)
- + ),
- +
- + TP_fast_assign(
- + __entry->vmid = vmid;
- + __entry->vcpuid = vcpuid;
- + ),
- +
- + TP_printk("vmid=%u, vcpuid=%u",
- + __entry->vmid, __entry->vcpuid)
- +);
- +
- TRACE_EVENT(kvm_hv_timer_state,
- TP_PROTO(unsigned int vcpu_id, unsigned int hv_timer_in_use),
- TP_ARGS(vcpu_id, hv_timer_in_use),
- diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
- index 5de2006..ef38b82 100644
- --- a/arch/x86/kvm/x86.c
- +++ b/arch/x86/kvm/x86.c
- @@ -10514,4 +10514,5 @@ u64 kvm_spec_ctrl_valid_bits(struct kvm_vcpu *vcpu)
- EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pi_irte_update);
- EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_unaccelerated_access);
- EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_incomplete_ipi);
- +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_ga_log);
- EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_apicv_update_request);
- From 93fd9666c269877fffb74e14f52792d9c000c1f2 Mon Sep 17 00:00:00 2001
- From: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
- Date: Fri, 21 Feb 2020 08:52:17 -0600
- Subject: kvm: x86: svm: Fix NULL pointer dereference when AVIC not enabled
- Launching VM w/ AVIC disabled together with pass-through device
- results in NULL pointer dereference bug with the following call trace.
- RIP: 0010:svm_refresh_apicv_exec_ctrl+0x17e/0x1a0 [kvm_amd]
- Call Trace:
- kvm_vcpu_update_apicv+0x44/0x60 [kvm]
- kvm_arch_vcpu_ioctl_run+0x3f4/0x1c80 [kvm]
- kvm_vcpu_ioctl+0x3d8/0x650 [kvm]
- do_vfs_ioctl+0xaa/0x660
- ? tomoyo_file_ioctl+0x19/0x20
- ksys_ioctl+0x67/0x90
- __x64_sys_ioctl+0x1a/0x20
- do_syscall_64+0x57/0x190
- entry_SYSCALL_64_after_hwframe+0x44/0xa9
- Investigation shows that this is due to the uninitialized usage of
- struct vapu_svm.ir_list in the svm_set_pi_irte_mode(), which is
- called from svm_refresh_apicv_exec_ctrl().
- The ir_list is initialized only if AVIC is enabled. So, fixes by
- adding a check if AVIC is enabled in the svm_refresh_apicv_exec_ctrl().
- Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=206579
- Fixes: 8937d762396d ("kvm: x86: svm: Add support to (de)activate posted interrupts.")
- Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
- Tested-by: Alex Williamson <alex.williamson@redhat.com>
- Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
- ---
- arch/x86/kvm/svm.c | 3 +++
- 1 file changed, 3 insertions(+)
- diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
- index bef0ba35f121..a391b29138f0 100644
- --- a/arch/x86/kvm/svm.c
- +++ b/arch/x86/kvm/svm.c
- @@ -5232,6 +5232,9 @@ static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
- struct vmcb *vmcb = svm->vmcb;
- bool activated = kvm_vcpu_apicv_active(vcpu);
- + if (!avic)
- + return;
- +
- if (activated) {
- /**
- * During AVIC temporary deactivation, guest could update
- --
- cgit 1.2-0.3.lf.el7
- From 7943f4acea3caf0b6d5b6cdfce7d5a2b4a9aa608 Mon Sep 17 00:00:00 2001
- From: Paolo Bonzini <pbonzini@redhat.com>
- Date: Tue, 25 Feb 2020 08:54:26 +0100
- Subject: KVM: SVM: allocate AVIC data structures based on kvm_amd module
- parameter
- Even if APICv is disabled at startup, the backing page and ir_list need
- to be initialized in case they are needed later. The only case in
- which this can be skipped is for userspace irqchip, and that must be
- done because avic_init_backing_page dereferences vcpu->arch.apic
- (which is NULL for userspace irqchip).
- Tested-by: rmuncrief@humanavance.com
- Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=206579
- Reviewed-by: Miaohe Lin <linmiaohe@huawei.com>
- Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
- ---
- arch/x86/kvm/svm.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
- diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
- index ad3f5b178a03..bd02526300ab 100644
- --- a/arch/x86/kvm/svm.c
- +++ b/arch/x86/kvm/svm.c
- @@ -2194,8 +2194,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
- static int avic_init_vcpu(struct vcpu_svm *svm)
- {
- int ret;
- + struct kvm_vcpu *vcpu = &svm->vcpu;
- - if (!kvm_vcpu_apicv_active(&svm->vcpu))
- + if (!avic || !irqchip_in_kernel(vcpu->kvm))
- return 0;
- ret = avic_init_backing_page(&svm->vcpu);
- --
- cgit 1.2-0.3.lf.el7
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement