提交 3548a259 编写于 作者: R Radim Krčmář 提交者: Paolo Bonzini

KVM: x86: avoid logical_map when it is invalid

We want to support mixed modes and the easiest solution is to avoid
optimizing those weird and unlikely scenarios.
Signed-off-by: NRadim Krčmář <rkrcmar@redhat.com>
Message-Id: <1423766494-26150-4-git-send-email-rkrcmar@redhat.com>
[Add comment above KVM_APIC_MODE_* defines. - Paolo]
Signed-off-by: NPaolo Bonzini <pbonzini@redhat.com>
上级 9ea369b0
...@@ -548,8 +548,20 @@ struct kvm_arch_memory_slot { ...@@ -548,8 +548,20 @@ struct kvm_arch_memory_slot {
struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1]; struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
}; };
/*
* We use as the mode the number of bits allocated in the LDR for the
* logical processor ID. It happens that these are all powers of two.
* This makes it is very easy to detect cases where the APICs are
* configured for multiple modes; in that case, we cannot use the map and
* hence cannot use kvm_irq_delivery_to_apic_fast either.
*/
#define KVM_APIC_MODE_XAPIC_CLUSTER 4
#define KVM_APIC_MODE_XAPIC_FLAT 8
#define KVM_APIC_MODE_X2APIC 16
struct kvm_apic_map { struct kvm_apic_map {
struct rcu_head rcu; struct rcu_head rcu;
u8 mode;
u8 ldr_bits; u8 ldr_bits;
/* fields bellow are used to decode ldr values in different modes */ /* fields bellow are used to decode ldr values in different modes */
u32 cid_shift, cid_mask, lid_mask; u32 cid_shift, cid_mask, lid_mask;
......
...@@ -133,6 +133,14 @@ static inline int kvm_apic_id(struct kvm_lapic *apic) ...@@ -133,6 +133,14 @@ static inline int kvm_apic_id(struct kvm_lapic *apic)
return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
} }
/* The logical map is definitely wrong if we have multiple
* modes at the same time. (Physical map is always right.)
*/
static inline bool kvm_apic_logical_map_valid(struct kvm_apic_map *map)
{
return !(map->mode & (map->mode - 1));
}
static void recalculate_apic_map(struct kvm *kvm) static void recalculate_apic_map(struct kvm *kvm)
{ {
struct kvm_apic_map *new, *old = NULL; struct kvm_apic_map *new, *old = NULL;
...@@ -162,16 +170,19 @@ static void recalculate_apic_map(struct kvm *kvm) ...@@ -162,16 +170,19 @@ static void recalculate_apic_map(struct kvm *kvm)
new->ldr_bits = 32; new->ldr_bits = 32;
new->cid_shift = 16; new->cid_shift = 16;
new->cid_mask = new->lid_mask = 0xffff; new->cid_mask = new->lid_mask = 0xffff;
new->mode |= KVM_APIC_MODE_X2APIC;
} else if (kvm_apic_get_reg(apic, APIC_LDR)) { } else if (kvm_apic_get_reg(apic, APIC_LDR)) {
if (kvm_apic_get_reg(apic, APIC_DFR) == if (kvm_apic_get_reg(apic, APIC_DFR) ==
APIC_DFR_CLUSTER) { APIC_DFR_CLUSTER) {
new->cid_shift = 4; new->cid_shift = 4;
new->cid_mask = 0xf; new->cid_mask = 0xf;
new->lid_mask = 0xf; new->lid_mask = 0xf;
new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER;
} else { } else {
new->cid_shift = 8; new->cid_shift = 8;
new->cid_mask = 0; new->cid_mask = 0;
new->lid_mask = 0xff; new->lid_mask = 0xff;
new->mode |= KVM_APIC_MODE_XAPIC_FLAT;
} }
} }
...@@ -201,6 +212,10 @@ static void recalculate_apic_map(struct kvm *kvm) ...@@ -201,6 +212,10 @@ static void recalculate_apic_map(struct kvm *kvm)
if (aid < ARRAY_SIZE(new->phys_map)) if (aid < ARRAY_SIZE(new->phys_map))
new->phys_map[aid] = apic; new->phys_map[aid] = apic;
if (!kvm_apic_logical_map_valid(new));
continue;
if (lid && cid < ARRAY_SIZE(new->logical_map)) if (lid && cid < ARRAY_SIZE(new->logical_map))
new->logical_map[cid][ffs(lid) - 1] = apic; new->logical_map[cid][ffs(lid) - 1] = apic;
} }
...@@ -718,7 +733,14 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, ...@@ -718,7 +733,14 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
dst = &map->phys_map[irq->dest_id]; dst = &map->phys_map[irq->dest_id];
} else { } else {
u32 mda = irq->dest_id << (32 - map->ldr_bits); u32 mda = irq->dest_id << (32 - map->ldr_bits);
u16 cid = apic_cluster_id(map, mda); u16 cid;
if (!kvm_apic_logical_map_valid(map)) {
ret = false;
goto out;
}
cid = apic_cluster_id(map, mda);
if (cid >= ARRAY_SIZE(map->logical_map)) if (cid >= ARRAY_SIZE(map->logical_map))
goto out; goto out;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册