diff options
author | Radim Krčmář <rkrcmar@redhat.com> | 2016-07-12 16:09:28 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-07-14 03:29:34 -0400 |
commit | c519265f2aa348b2f1b9ecf8fbe20bb7c0fb102e (patch) | |
tree | d8e9820f18f59eb4b6400e768280a88c7e88f50a | |
parent | 3713131345fbea291cbd859d248e06ed77815962 (diff) |
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.
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
[Expand kvm_apic_mda comment. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | Documentation/virtual/kvm/api.txt | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 53 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 5 | ||||
-rw-r--r-- | include/uapi/linux/kvm.h | 1 |
5 files changed, 52 insertions, 14 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index e34e51fa28b0..c4d2fb0e28de 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt | |||
@@ -3844,12 +3844,18 @@ Returns: 0 on success, -EINVAL when args[0] contains invalid features | |||
3844 | Valid feature flags in args[0] are | 3844 | Valid 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 | ||
3848 | Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of | 3849 | Enabling KVM_X2APIC_API_USE_32BIT_IDS changes the behavior of |
3849 | KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC, | 3850 | KVM_SET_GSI_ROUTING, KVM_SIGNAL_MSI, KVM_SET_LAPIC, and KVM_GET_LAPIC, |
3850 | allowing the use of 32-bit APIC IDs. See KVM_CAP_X2APIC_API in their | 3851 | allowing the use of 32-bit APIC IDs. See KVM_CAP_X2APIC_API in their |
3851 | respective sections. | 3852 | respective sections. |
3852 | 3853 | ||
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. | ||
3853 | 3859 | ||
3854 | 3860 | ||
3855 | 8. Other capabilities. | 3861 | 8. Other capabilities. |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7c00ba3242d7..074b5c760327 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -784,6 +784,7 @@ struct kvm_arch { | |||
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 | ||
789 | struct kvm_vm_stat { | 790 | struct kvm_vm_stat { |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index d27a7829a4ce..a16e0bb95d28 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -616,17 +616,30 @@ static bool kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda) | |||
616 | } | 616 | } |
617 | } | 617 | } |
618 | 618 | ||
619 | /* KVM APIC implementation has two quirks | 619 | /* 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 | */ |
623 | static u32 kvm_apic_mda(unsigned int dest_id, struct kvm_lapic *source, | 635 | static 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, | |||
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) | |||
688 | } | 701 | } |
689 | } | 702 | } |
690 | 703 | ||
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 | |||
691 | /* Return true if the interrupt can be handled by using *bitmap as index mask | 723 | /* 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, | |||
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, | |||
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) { |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d86f563a6896..f0d23622bc4e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -90,7 +90,8 @@ static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE); | |||
90 | #define VM_STAT(x) offsetof(struct kvm, stat.x), KVM_STAT_VM | 90 | #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_VCPU | 91 | #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 | ||
95 | static void update_cr8_intercept(struct kvm_vcpu *vcpu); | 96 | static void update_cr8_intercept(struct kvm_vcpu *vcpu); |
96 | static void process_nmi(struct kvm_vcpu *vcpu); | 97 | static void process_nmi(struct kvm_vcpu *vcpu); |
@@ -3811,6 +3812,8 @@ split_irqchip_unlock: | |||
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; |
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index f704403e19a0..4f8030e5b05d 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h | |||
@@ -1315,5 +1315,6 @@ struct kvm_assigned_msix_entry { | |||
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 */ |