aboutsummaryrefslogtreecommitdiff
path: root/arch/x86/kvm/lapic.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2014-11-06 10:51:45 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2014-11-17 12:16:19 +0100
commita3e339e1cec899908f516a4ebde64cac500b0c45 (patch)
tree5317dfdb5f8ae44b3198ac5e52c2afcfd20f9fde /arch/x86/kvm/lapic.c
parent173beedc1601f51dae9d579aa7a414c5aa8f700b (diff)
KVM: compute correct map even if all APICs are software disabled
Logical destination mode can be used to send NMI IPIs even when all APICs are software disabled, so if all APICs are software disabled we should still look at the DFRs. So the DFRs should all be the same, even if some or all APICs are software disabled. However, the SDM does not say this, so tweak the logic as follows: - if one APIC is enabled and has LDR != 0, use that one to build the map. This picks the right DFR in case an OS is only setting it for the software-enabled APICs, or in case an OS is using logical addressing on some APICs while leaving the rest in reset state (using LDR was suggested by Radim). - if all APICs are disabled, pick a random one to build the map. We use the last one with LDR != 0 for simplicity. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r--arch/x86/kvm/lapic.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index c98b44d0ffe6..6e8ce5a1a05d 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -160,29 +160,34 @@ static void recalculate_apic_map(struct kvm *kvm)
if (!kvm_apic_present(vcpu))
continue;
- /*
- * All APICs have to be configured in the same mode by an OS.
- * We take advatage of this while building logical id loockup
- * table. After reset APICs are in xapic/flat mode, so if we
- * find apic with different setting we assume this is the mode
- * OS wants all apics to be in; build lookup table accordingly.
- */
if (apic_x2apic_mode(apic)) {
new->ldr_bits = 32;
new->cid_shift = 16;
new->cid_mask = (1 << KVM_X2APIC_CID_BITS) - 1;
new->lid_mask = 0xffff;
new->broadcast = X2APIC_BROADCAST;
- break;
- } else if (kvm_apic_sw_enabled(apic)) {
+ } else if (kvm_apic_get_reg(apic, APIC_LDR)) {
if (kvm_apic_get_reg(apic, APIC_DFR) ==
APIC_DFR_CLUSTER) {
new->cid_shift = 4;
new->cid_mask = 0xf;
new->lid_mask = 0xf;
+ } else {
+ new->cid_shift = 8;
+ new->cid_mask = 0;
+ new->lid_mask = 0xff;
}
- break;
}
+
+ /*
+ * All APICs have to be configured in the same mode by an OS.
+ * We take advatage of this while building logical id loockup
+ * table. After reset APICs are in software disabled mode, so if
+ * we find apic with different setting we assume this is the mode
+ * OS wants all apics to be in; build lookup table accordingly.
+ */
+ if (kvm_apic_sw_enabled(apic))
+ break;
}
kvm_for_each_vcpu(i, vcpu, kvm) {