History

KVM: x86: add a flag to disable KVM x2apic broadcast quirk

Add KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK as a feature flag to KVM_CAP_X2APIC_API. The quirk made KVM interpret 0xff as a broadcast even in x2APIC mode. The enableable capability is needed in order to support standard x2APIC and remain backward compatible.

Radim Krčmář committed 10 years ago

Commit c5192651 parent 37131315 files · +52 −14Browse files

Unified · Split

5 files
  1. Documentation/virtual/kvm/api.txt +6 −0
  2. arch/x86/include/asm/kvm_host.h +1 −0
  3. arch/x86/kvm/lapic.c +40 −13
  4. arch/x86/kvm/x86.c +4 −1
  5. include/uapi/linux/kvm.h +1 −0
Documentation/virtual/kvm/api.txt+6−0
@@ -3844,12 +3844,18 @@ Returns: 0 on success, -EINVAL when args[0] contains invalid features · 3843 unmodified lines
3844Valid feature flags in args[0] are3844Valid feature flags in args[0] are
3845 3845
3846#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)3846#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
3847#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
3847 3848
3848Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of3849Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of
3849KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC,3850KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC,
3850allowing the use of 32-bit APIC IDs. See KVM_CAP_X2APIC_API in their3851allowing the use of 32-bit APIC IDs. See KVM_CAP_X2APIC_API in their
3851respective sections.3852respective sections.
3852 3853
3854KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK must be enabled for x2APIC to work
3855in logical mode or with more than 255 VCPUs. Otherwise, KVM treats 0xff
3856as a broadcast even in x2APIC mode in order to support physical x2APIC
3857without interrupt remapping. This is undesirable in logical mode,
3858where 0xff represents CPUs 0-7 in cluster 0.
3853 3859
3854 3860
38558. Other capabilities.38618. Other capabilities.
arch/x86/include/asm/kvm_host.h+1−0
@@ -784,6 +784,7 @@ struct kvm_arch { · 783 unmodified lines
784 struct page *avic_physical_id_table_page;784 struct page *avic_physical_id_table_page;
785 785
786 bool x2apic_format;786 bool x2apic_format;
787 bool x2apic_broadcast_quirk_disabled;
787};788};
788 789
789struct kvm_vm_stat {790struct kvm_vm_stat {
arch/x86/kvm/lapic.c+40−13
@@ -616,17 +616,30 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) · 615 unmodified lines
616 }616 }
617}617}
618 618
619/* KVM APIC implementation has two quirks619/* The KVM local APIC implementation has two quirks:
620 * - dest always begins at 0 while xAPIC MDA has offset 24,620 *
621 * - IOxAPIC messages have to be delivered (directly) to x2APIC.621 * - the xAPIC MDA stores the destination at bits 24-31, while this
622 * is not true of struct kvm_lapic_irq's dest_id field. This is
623 * just a quirk in the API and is not problematic.
624 *
625 * - in-kernel IOAPIC messages have to be delivered directly to
626 * x2APIC, because the kernel does not support interrupt remapping.
627 * In order to support broadcast without interrupt remapping, x2APIC
628 * rewrites the destination of non-IPI messages from APIC_BROADCAST
629 * to X2APIC_BROADCAST.
630 *
631 * The broadcast quirk can be disabled with KVM_CAP_X2APIC_API. This is
632 * important when userspace wants to use x2APIC-format MSIs, because
633 * APIC_BROADCAST (0xff) is a legal route for "cluster 0, CPUs 0-7".
622 */634 */
623static u32 kvm_apic_mda(unsigned int dest_id, struct kvm_lapic *source,635static u32 kvm_apic_mda(struct kvm_vcpu *vcpu, unsigned int dest_id,
624 struct kvm_lapic *target)636 struct kvm_lapic *source, struct kvm_lapic *target)
625{637{
626 bool ipi = source != NULL;638 bool ipi = source != NULL;
627 bool x2apic_mda = apic_x2apic_mode(ipi ? source : target);639 bool x2apic_mda = apic_x2apic_mode(ipi ? source : target);
628 640
629 if (!ipi && dest_id == APIC_BROADCAST && x2apic_mda)641 if (!vcpu->kvm->arch.x2apic_broadcast_quirk_disabled &&
642 !ipi && dest_id == APIC_BROADCAST && x2apic_mda)
630 return X2APIC_BROADCAST;643 return X2APIC_BROADCAST;
631 644
632 return x2apic_mda ? dest_id : SET_APIC_DEST_FIELD(dest_id);645 return x2apic_mda ? dest_id : SET_APIC_DEST_FIELD(dest_id);
@@ -636,7 +649,7 @@ bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, · 3 unmodified lines
636 int short_hand, unsigned int dest, int dest_mode)649 int short_hand, unsigned int dest, int dest_mode)
637{650{
638 struct kvm_lapic *target = vcpu->arch.apic;651 struct kvm_lapic *target = vcpu->arch.apic;
639 u32 mda = kvm_apic_mda(dest, source, target);652 u32 mda = kvm_apic_mda(vcpu, dest, source, target);
640 653
641 apic_debug("target %p, source %p, dest 0x%x, "654 apic_debug("target %p, source %p, dest 0x%x, "
642 "dest_mode 0x%x, short_hand 0x%x\n",655 "dest_mode 0x%x, short_hand 0x%x\n",
@@ -688,6 +701,25 @@ static void kvm_apic_disabled_lapic_found(struct kvm *kvm) · 45 unmodified lines
688 }701 }
689}702}
690 703
704static bool kvm_apic_is_broadcast_dest(struct kvm *kvm, struct kvm_lapic **src,
705 struct kvm_lapic_irq *irq, struct kvm_apic_map *map)
706{
707 if (kvm->arch.x2apic_broadcast_quirk_disabled) {
708 if ((irq->dest_id == APIC_BROADCAST &&
709 map->mode != KVM_APIC_MODE_X2APIC))
710 return true;
711 if (irq->dest_id == X2APIC_BROADCAST)
712 return true;
713 } else {
714 bool x2apic_ipi = src && *src && apic_x2apic_mode(*src);
715 if (irq->dest_id == (x2apic_ipi ?
716 X2APIC_BROADCAST : APIC_BROADCAST))
717 return true;
718 }
719
720 return false;
721}
722
691/* Return true if the interrupt can be handled by using *bitmap as index mask723/* Return true if the interrupt can be handled by using *bitmap as index mask
692 * for valid destinations in *dst array.724 * for valid destinations in *dst array.
693 * Return false if kvm_apic_map_get_dest_lapic did nothing useful.725 * Return false if kvm_apic_map_get_dest_lapic did nothing useful.
@@ -701,7 +733,6 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm, · 7 unmodified lines
701 unsigned long *bitmap)733 unsigned long *bitmap)
702{734{
703 int i, lowest;735 int i, lowest;
704 bool x2apic_ipi;
705 736
706 if (irq->shorthand == APIC_DEST_SELF && src) {737 if (irq->shorthand == APIC_DEST_SELF && src) {
707 *dst = src;738 *dst = src;
@@ -710,11 +741,7 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm, · 2 unmodified lines
710 } else if (irq->shorthand)741 } else if (irq->shorthand)
711 return false;742 return false;
712 743
713 x2apic_ipi = src && *src && apic_x2apic_mode(*src);744 if (!map || kvm_apic_is_broadcast_dest(kvm, src, irq, map))
714 if (irq->dest_id == (x2apic_ipi ? X2APIC_BROADCAST : APIC_BROADCAST))
715 return false;
716
717 if (!map)
718 return false;745 return false;
719 746
720 if (irq->dest_mode == APIC_DEST_PHYSICAL) {747 if (irq->dest_mode == APIC_DEST_PHYSICAL) {
arch/x86/kvm/x86.c+4−1
@@ -90,7 +90,8 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE); · 89 unmodified lines
90#define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM90#define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM
91#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU91#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
92 92
93#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS)93#define KVM_X2APIC_API_VALID_FLAGS (KVM_X2APIC_API_USE_32BIT_IDS | \
94 KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
94 95
95static void update_cr8_intercept(struct kvm_vcpu *vcpu);96static void update_cr8_intercept(struct kvm_vcpu *vcpu);
96static void process_nmi(struct kvm_vcpu *vcpu);97static void process_nmi(struct kvm_vcpu *vcpu);
@@ -3811,6 +3812,8 @@ split_irqchip_unlock: · 3714 unmodified lines
3811 3812
3812 if (cap->args[0] & KVM_X2APIC_API_USE_32BIT_IDS)3813 if (cap->args[0] & KVM_X2APIC_API_USE_32BIT_IDS)
3813 kvm->arch.x2apic_format = true;3814 kvm->arch.x2apic_format = true;
3815 if (cap->args[0] & KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
3816 kvm->arch.x2apic_broadcast_quirk_disabled = true;
3814 3817
3815 r = 0;3818 r = 0;
3816 break;3819 break;
include/uapi/linux/kvm.h+1−0
@@ -1315,5 +1315,6 @@ struct kvm_assigned_msix_entry { · 1314 unmodified lines
1315};1315};
1316 1316
1317#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)1317#define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
1318#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
1318 1319
1319#endif /* __LINUX_KVM_H */1320#endif /* __LINUX_KVM_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t