| @@ -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 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". |
| 622 | 634 | */ |
| 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) |
| 625 | 637 | { |
| 626 | 638 | bool ipi = source != NULL; |
| 627 | 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 | 643 | return X2APIC_BROADCAST; |
| 631 | 644 | |
| 632 | 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 | 649 | int short_hand, unsigned int dest, int dest_mode) |
| 637 | 650 | { |
| 638 | 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 | 654 | apic_debug("target %p, source %p, dest 0x%x, " |
| 642 | 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 | |
| 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 | 723 | /* Return true if the interrupt can be handled by using *bitmap as index mask |
| 692 | 724 | * for valid destinations in *dst array. |
| 693 | 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 | 733 | unsigned long *bitmap) |
| 702 | 734 | { |
| 703 | 735 | int i, lowest; |
| 704 | | − bool x2apic_ipi; |
| 705 | 736 | |
| 706 | 737 | if (irq->shorthand == APIC_DEST_SELF && src) { |
| 707 | 738 | *dst = src; |
| @@ -710,11 +741,7 @@ static inline bool kvm_apic_map_get_dest_lapic(struct kvm *kvm, · 2 unmodified lines |
| 710 | 741 | } else if (irq->shorthand) |
| 711 | 742 | return false; |
| 712 | 743 | |
| 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)) |
| 718 | 745 | return false; |
| 719 | 746 | |
| 720 | 747 | if (irq->dest_mode == APIC_DEST_PHYSICAL) { |