Skip to content

Commit

Permalink
KVM: x86: avoid logical_map when it is invalid
Browse files Browse the repository at this point in the history
We want to support mixed modes and the easiest solution is to avoid
optimizing those weird and unlikely scenarios.

Signed-off-by: Radim 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: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
Radim Krčmář authored and Paolo Bonzini committed Apr 8, 2015
1 parent 9ea369b commit 3548a25
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
12 changes: 12 additions & 0 deletions arch/x86/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,20 @@ struct kvm_arch_memory_slot {
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 rcu_head rcu;
u8 mode;
u8 ldr_bits;
/* fields bellow are used to decode ldr values in different modes */
u32 cid_shift, cid_mask, lid_mask;
Expand Down
24 changes: 23 additions & 1 deletion arch/x86/kvm/lapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,14 @@ static inline int kvm_apic_id(struct kvm_lapic *apic)
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)
{
struct kvm_apic_map *new, *old = NULL;
Expand Down Expand Up @@ -162,16 +170,19 @@ static void recalculate_apic_map(struct kvm *kvm)
new->ldr_bits = 32;
new->cid_shift = 16;
new->cid_mask = new->lid_mask = 0xffff;
new->mode |= KVM_APIC_MODE_X2APIC;
} 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;
new->mode |= KVM_APIC_MODE_XAPIC_CLUSTER;
} else {
new->cid_shift = 8;
new->cid_mask = 0;
new->lid_mask = 0xff;
new->mode |= KVM_APIC_MODE_XAPIC_FLAT;
}
}

Expand Down Expand Up @@ -201,6 +212,10 @@ static void recalculate_apic_map(struct kvm *kvm)

if (aid < ARRAY_SIZE(new->phys_map))
new->phys_map[aid] = apic;

if (!kvm_apic_logical_map_valid(new));
continue;

if (lid && cid < ARRAY_SIZE(new->logical_map))
new->logical_map[cid][ffs(lid) - 1] = apic;
}
Expand Down Expand Up @@ -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];
} else {
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))
goto out;
Expand Down

0 comments on commit 3548a25

Please sign in to comment.