Skip to content

Commit fc61b80

Browse files
Gleb Natapovavikivity
authored andcommitted
KVM: Add Directed EOI support to APIC emulation
Directed EOI is specified by x2APIC, but is available even when lapic is in xAPIC mode. Signed-off-by: Gleb Natapov <[email protected]> Signed-off-by: Avi Kivity <[email protected]>
1 parent cb24772 commit fc61b80

File tree

5 files changed

+39
-10
lines changed

5 files changed

+39
-10
lines changed

arch/x86/include/asm/apicdef.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#define APIC_LVR 0x30
1616
#define APIC_LVR_MASK 0xFF00FF
17+
#define APIC_LVR_DIRECTED_EOI (1 << 24)
1718
#define GET_APIC_VERSION(x) ((x) & 0xFFu)
1819
#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu)
1920
#ifdef CONFIG_X86_32
@@ -40,6 +41,7 @@
4041
#define APIC_DFR_CLUSTER 0x0FFFFFFFul
4142
#define APIC_DFR_FLAT 0xFFFFFFFFul
4243
#define APIC_SPIV 0xF0
44+
#define APIC_SPIV_DIRECTED_EOI (1 << 12)
4345
#define APIC_SPIV_FOCUS_DISABLED (1 << 9)
4446
#define APIC_SPIV_APIC_ENABLED (1 << 8)
4547
#define APIC_ISR 0x100

arch/x86/kvm/lapic.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "kvm_cache_regs.h"
3636
#include "irq.h"
3737
#include "trace.h"
38+
#include "x86.h"
3839

3940
#ifndef CONFIG_X86_64
4041
#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
@@ -142,6 +143,21 @@ static inline int apic_lvt_nmi_mode(u32 lvt_val)
142143
return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI;
143144
}
144145

146+
void kvm_apic_set_version(struct kvm_vcpu *vcpu)
147+
{
148+
struct kvm_lapic *apic = vcpu->arch.apic;
149+
struct kvm_cpuid_entry2 *feat;
150+
u32 v = APIC_VERSION;
151+
152+
if (!irqchip_in_kernel(vcpu->kvm))
153+
return;
154+
155+
feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0);
156+
if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31))))
157+
v |= APIC_LVR_DIRECTED_EOI;
158+
apic_set_reg(apic, APIC_LVR, v);
159+
}
160+
145161
static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
146162
LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */
147163
LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */
@@ -442,9 +458,11 @@ static void apic_set_eoi(struct kvm_lapic *apic)
442458
trigger_mode = IOAPIC_LEVEL_TRIG;
443459
else
444460
trigger_mode = IOAPIC_EDGE_TRIG;
445-
mutex_lock(&apic->vcpu->kvm->irq_lock);
446-
kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
447-
mutex_unlock(&apic->vcpu->kvm->irq_lock);
461+
if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)) {
462+
mutex_lock(&apic->vcpu->kvm->irq_lock);
463+
kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
464+
mutex_unlock(&apic->vcpu->kvm->irq_lock);
465+
}
448466
}
449467

450468
static void apic_send_ipi(struct kvm_lapic *apic)
@@ -694,8 +712,11 @@ static int apic_mmio_write(struct kvm_io_device *this,
694712
apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
695713
break;
696714

697-
case APIC_SPIV:
698-
apic_set_reg(apic, APIC_SPIV, val & 0x3ff);
715+
case APIC_SPIV: {
716+
u32 mask = 0x3ff;
717+
if (apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
718+
mask |= APIC_SPIV_DIRECTED_EOI;
719+
apic_set_reg(apic, APIC_SPIV, val & mask);
699720
if (!(val & APIC_SPIV_APIC_ENABLED)) {
700721
int i;
701722
u32 lvt_val;
@@ -710,7 +731,7 @@ static int apic_mmio_write(struct kvm_io_device *this,
710731

711732
}
712733
break;
713-
734+
}
714735
case APIC_ICR:
715736
/* No delay here, so we always clear the pending bit */
716737
apic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
@@ -837,7 +858,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
837858
hrtimer_cancel(&apic->lapic_timer.timer);
838859

839860
apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
840-
apic_set_reg(apic, APIC_LVR, APIC_VERSION);
861+
kvm_apic_set_version(apic->vcpu);
841862

842863
for (i = 0; i < APIC_LVT_NUM; i++)
843864
apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
@@ -1041,7 +1062,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
10411062

10421063
apic->base_address = vcpu->arch.apic_base &
10431064
MSR_IA32_APICBASE_BASE;
1044-
apic_set_reg(apic, APIC_LVR, APIC_VERSION);
1065+
kvm_apic_set_version(vcpu);
1066+
10451067
apic_update_ppr(apic);
10461068
hrtimer_cancel(&apic->lapic_timer.timer);
10471069
update_divide_count(apic);

arch/x86/kvm/lapic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
2929
void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
3030
void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
3131
u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
32+
void kvm_apic_set_version(struct kvm_vcpu *vcpu);
3233

3334
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
3435
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);

arch/x86/kvm/x86.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffffeULL;
7979

8080
static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
8181
struct kvm_cpuid_entry2 __user *entries);
82-
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
83-
u32 function, u32 index);
8482

8583
struct kvm_x86_ops *kvm_x86_ops;
8684
EXPORT_SYMBOL_GPL(kvm_x86_ops);
@@ -1373,6 +1371,7 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
13731371
vcpu->arch.cpuid_nent = cpuid->nent;
13741372
cpuid_fix_nx_cap(vcpu);
13751373
r = 0;
1374+
kvm_apic_set_version(vcpu);
13761375

13771376
out_free:
13781377
vfree(cpuid_entries);
@@ -1394,6 +1393,7 @@ static int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
13941393
cpuid->nent * sizeof(struct kvm_cpuid_entry2)))
13951394
goto out;
13961395
vcpu->arch.cpuid_nent = cpuid->nent;
1396+
kvm_apic_set_version(vcpu);
13971397
return 0;
13981398

13991399
out:

arch/x86/kvm/x86.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ static inline bool kvm_exception_is_soft(unsigned int nr)
3131
{
3232
return (nr == BP_VECTOR) || (nr == OF_VECTOR);
3333
}
34+
35+
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
36+
u32 function, u32 index);
37+
3438
#endif

0 commit comments

Comments
 (0)