aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/lapic.c
diff options
context:
space:
mode:
authorRadim Krčmář <rkrcmar@redhat.com>2015-02-12 13:41:32 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2015-04-08 04:47:00 -0400
commit9ea369b032d87b88f1a47187b51ad4321dea5766 (patch)
tree96f543186a9a943975ca97b7fca20237875f23a5 /arch/x86/kvm/lapic.c
parent03d2249ea60818e97475ac529aa183cf130935bb (diff)
KVM: x86: fix mixed APIC mode broadcast
Broadcast allowed only one global APIC mode, but mixed modes are theoretically possible. x2APIC IPI doesn't mean 0xff as broadcast, the rest does. x2APIC broadcasts are accepted by xAPIC. If we take SDM to be logical, even addreses beginning with 0xff should be accepted, but real hardware disagrees. This patch aims for simple code by considering most of real behavior as undefined. Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> Message-Id: <1423766494-26150-3-git-send-email-rkrcmar@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r--arch/x86/kvm/lapic.c9
1 files changed, 4 insertions, 5 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 69569744745d..d45f00ba7440 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -151,7 +151,6 @@ static void recalculate_apic_map(struct kvm *kvm)
151 new->cid_shift = 8; 151 new->cid_shift = 8;
152 new->cid_mask = 0; 152 new->cid_mask = 0;
153 new->lid_mask = 0xff; 153 new->lid_mask = 0xff;
154 new->broadcast = APIC_BROADCAST;
155 154
156 kvm_for_each_vcpu(i, vcpu, kvm) { 155 kvm_for_each_vcpu(i, vcpu, kvm) {
157 struct kvm_lapic *apic = vcpu->arch.apic; 156 struct kvm_lapic *apic = vcpu->arch.apic;
@@ -163,7 +162,6 @@ static void recalculate_apic_map(struct kvm *kvm)
163 new->ldr_bits = 32; 162 new->ldr_bits = 32;
164 new->cid_shift = 16; 163 new->cid_shift = 16;
165 new->cid_mask = new->lid_mask = 0xffff; 164 new->cid_mask = new->lid_mask = 0xffff;
166 new->broadcast = X2APIC_BROADCAST;
167 } else if (kvm_apic_get_reg(apic, APIC_LDR)) { 165 } else if (kvm_apic_get_reg(apic, APIC_LDR)) {
168 if (kvm_apic_get_reg(apic, APIC_DFR) == 166 if (kvm_apic_get_reg(apic, APIC_DFR) ==
169 APIC_DFR_CLUSTER) { 167 APIC_DFR_CLUSTER) {
@@ -690,6 +688,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
690 struct kvm_lapic **dst; 688 struct kvm_lapic **dst;
691 int i; 689 int i;
692 bool ret = false; 690 bool ret = false;
691 bool x2apic_ipi = src && apic_x2apic_mode(src);
693 692
694 *r = -1; 693 *r = -1;
695 694
@@ -701,15 +700,15 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
701 if (irq->shorthand) 700 if (irq->shorthand)
702 return false; 701 return false;
703 702
703 if (irq->dest_id == (x2apic_ipi ? X2APIC_BROADCAST : APIC_BROADCAST))
704 return false;
705
704 rcu_read_lock(); 706 rcu_read_lock();
705 map = rcu_dereference(kvm->arch.apic_map); 707 map = rcu_dereference(kvm->arch.apic_map);
706 708
707 if (!map) 709 if (!map)
708 goto out; 710 goto out;
709 711
710 if (irq->dest_id == map->broadcast)
711 goto out;
712
713 ret = true; 712 ret = true;
714 713
715 if (irq->dest_mode == APIC_DEST_PHYSICAL) { 714 if (irq->dest_mode == APIC_DEST_PHYSICAL) {