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
38443844 Valid feature flags in args[0] are
38453845
38463846 #define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
3847+#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
38473848
38483849 Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of
38493850 KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC,
38503851 allowing the use of 32-bit APIC IDs. See KVM_CAP_X2APIC_API in their
38513852 respective sections.
38523853
3854+KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK must be enabled for x2APIC to work
3855+in logical mode or with more than 255 VCPUs. Otherwise, KVM treats 0xff
3856+as a broadcast even in x2APIC mode in order to support physical x2APIC
3857+without interrupt remapping. This is undesirable in logical mode,
3858+where 0xff represents CPUs 0-7 in cluster 0.
38533859
38543860
38553861 8. Other capabilities.
arch/x86/include/asm/kvm_host.h+1−0
@@ -784,6 +784,7 @@ struct kvm_arch { · 783 unmodified lines
784784 struct page *avic_physical_id_table_page;
785785
786786 bool x2apic_format;
787+ bool x2apic_broadcast_quirk_disabled;
787788 };
788789
789790 struct 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
616616 }
617617 }
618618
619−/* KVM APIC implementation has two quirks
620− * - dest always begins at 0 while xAPIC MDA has offset 24,
621− * - IOxAPIC messages have to be delivered (directly) to x2APIC.
619+/* The KVM local APIC implementation has two quirks:
620+ *
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".
622634 */
623−static u32 kvm_apic_mda(unsigned int dest_id, struct kvm_lapic *source,
624− struct kvm_lapic *target)
635+static u32 kvm_apic_mda(struct kvm_vcpu *vcpu, unsigned int dest_id,
636+ struct kvm_lapic *source, struct kvm_lapic *target)
625637 {
626638 bool ipi = source != NULL;
627639 bool x2apic_mda = apic_x2apic_mode(ipi ? source : target);
628640
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)
630643 return X2APIC_BROADCAST;
631644
632645 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
636649 int short_hand, unsigned int dest, int dest_mode)
637650 {
638651 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);
640653
641654 apic_debug("target %p, source %p, dest 0x%x, "
642655 "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
688701 }
689702 }
690703
704+static 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+
691723 /* Return true if the interrupt can be handled by using *bitmap as index mask
692724 * for valid destinations in *dst array.
693725 * 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
701733 unsigned long *bitmap)
702734 {
703735 int i, lowest;
704− bool x2apic_ipi;
705736
706737 if (irq->shorthand == APIC_DEST_SELF && src) {
707738 *dst = src;
@@ -710,11 +741,7 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm, · 2 unmodified lines
710741 } else if (irq->shorthand)
711742 return false;
712743
713− x2apic_ipi = src && *src && apic_x2apic_mode(*src);
714− if (irq->dest_id == (x2apic_ipi ? X2APIC_BROADCAST : APIC_BROADCAST))
715− return false;
716−
717− if (!map)
744+ if (!map || kvm_apic_is_broadcast_dest(kvm, src, irq, map))
718745 return false;
719746
720747 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
9090 #define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM
9191 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
9292
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)
9495
9596 static void update_cr8_intercept(struct kvm_vcpu *vcpu);
9697 static void process_nmi(struct kvm_vcpu *vcpu);
@@ -3811,6 +3812,8 @@ split_irqchip_unlock: · 3714 unmodified lines
38113812
38123813 if (cap->args[0] & KVM_X2APIC_API_USE_32BIT_IDS)
38133814 kvm->arch.x2apic_format = true;
3815+ if (cap->args[0] & KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK)
3816+ kvm->arch.x2apic_broadcast_quirk_disabled = true;
38143817
38153818 r = 0;
38163819 break;
include/uapi/linux/kvm.h+1−0
@@ -1315,5 +1315,6 @@ struct kvm_assigned_msix_entry { · 1314 unmodified lines
13151315 };
13161316
13171317 #define KVM_X2APIC_API_USE_32BIT_IDS (1ULL << 0)
1318+#define KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK (1ULL << 1)
13181319
13191320 #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