aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/x86/include/asm/kvm_host.h2
-rw-r--r--arch/x86/kvm/lapic.c9
2 files changed, 5 insertions, 6 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 8d92e3bab118..5b1bc97a258a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -552,7 +552,7 @@ struct kvm_apic_map {
552 struct rcu_head rcu; 552 struct rcu_head rcu;
553 u8 ldr_bits; 553 u8 ldr_bits;
554 /* fields bellow are used to decode ldr values in different modes */ 554 /* fields bellow are used to decode ldr values in different modes */
555 u32 cid_shift, cid_mask, lid_mask, broadcast; 555 u32 cid_shift, cid_mask, lid_mask;
556 struct kvm_lapic *phys_map[256]; 556 struct kvm_lapic *phys_map[256];
557 /* first index is cluster id second is cpu id in a cluster */ 557 /* first index is cluster id second is cpu id in a cluster */
558 struct kvm_lapic *logical_map[16][16]; 558 struct kvm_lapic *logical_map[16][16];
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) {