Skip to contentSkip to conversation

kvm: eoi optimization support

PATCH Superseded Michael S. Tsirkin 2 participants 18 messages Jun 14, 2012 – Jun 18, 2012

Subsystems (6)
Documentation x86 KVM KVM x86 +2 more subsystems

v7 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v7 cover kvm: eoi optimization support

I'm looking at reducing the interrupt overhead for virtualized guests:
some workloads spend a large part of their time processing interrupts.

On kvm, an EOI write from the guest causes an expensive exit to host; we avoid this using shared memory.

The patches work fine on my boxes. See individual patches for perf tests. You need to patch qemu to whitelist the kvm feature. qemu patch was sent separately.

The patches are against Linus's master and apply to kvm.git cleanly. The last patch in the series, supplying the host part, also depends on the ISR optimization patch that I have for convenience included in the series (patch 2),
I also included a documentation patch (patch 1) - it is here since it clarifies patch 2. This revision does not yet address Thomas's idea of reworking the APIC page handling. Changes to this optimization would require reworking this last patch in the series.

The rest of the patchset has not changed significantly since v2.

Thanks,
MST

changes from v6:
Address Marcelo's comments:
marcelo's comments for isr optimization: isr_cache -> highest_* marcelo's comments for host side eoi: rename isr_cache->highest_* kvm eoi msr doc: fix typo pointed out by marcelo
isr optimization: add comment to address marcelo's request
kvm: don't make lapic attention check unlikely. at marcelo's request eoi host side: remove unlikely annotations

Changes from v5:
Clear PV EOI when we cancel interrupts.
Pointed out by Gleb.
Always set ISR cache when we inject an interrupt.
Suggested by Ronen Hod.

Changes from v4:
Turn off PV EOI on each exit. Turn it back on when safe.
Suggested by Avi.
Address bug with nested interrupts pointed out by Marcelo.

Changes from v3:
Address review comments by Marcelo:
Multiple cosmetic changes eoi -> pv_eoi Added multiple comments
Changes from v2:
Kill guest with GP on an illegal MSR value Add documentation

Changes from v1:
Add host side patch to series
Remove kvm-specific __test_and_clear_bit, document that x86 one does what we want already Clear msr on cpu unplug

Michael S. Tsirkin (8):
kvm: document lapic regs field
kvm: optimize ISR lookups
kvm_para: guest side for eoi avoidance x86/bitops: note on __test_and_clear_bit atomicity
kvm: eoi msi documentation
kvm: only sync when attention bits set
kvm: rearrange injection cancelling code
kvm: host side for eoi optimization

 Documentation/virtual/kvm/msr.txt |  32 +++++++
 arch/x86/include/asm/bitops.h     |  13 ++-
 arch/x86/include/asm/kvm_host.h   |  12 +++
 arch/x86/include/asm/kvm_para.h   |   7 ++
 arch/x86/kernel/kvm.c             |  51 +++++++++-
 arch/x86/kvm/cpuid.c              |   1 +
 arch/x86/kvm/lapic.c              | 193 ++++++++++++++++++++++++++++++++++++--
 arch/x86/kvm/lapic.h              |  11 +++
 arch/x86/kvm/trace.h              |  34 +++++++
 arch/x86/kvm/x86.c                |  20 +++-
 10 files changed, 358 insertions(+), 16 deletions(-)
Signature · 1 line
MST
#1 lore raw

PATCH v7 1/8 kvm: document lapic regs field

---
 arch/x86/kvm/lapic.h | 5 +++++
 1 file changed, 5 insertions(+)
arch/x86/kvm/lapic.h +5 -0
index 6f4ce25..d29da25 100644
@@ -13,6 +13,11 @@ struct kvm_lapic {
 	u32 divide_count;
 	struct kvm_vcpu *vcpu;
 	bool irr_pending;
+	/**
+	 * APIC register page.  The layout matches the register layout seen by
+	 * the guest 1:1, because it is accessed by the vmx microcode.
+	 * Note: Only one register, the TPR, is used by the microcode.
+	 */
 	void *regs;
 	gpa_t vapic_addr;
 	struct page *vapic_page;
Signature · 1 line
MST
#2 lore raw

PATCH v7 2/8 kvm: optimize ISR lookups

In reply to Michael S. Tsirkin

We perform ISR lookups twice: during interrupt injection and on EOI. Typical workloads only have a single bit set there. So we can avoid ISR scans by
1. counting bits as we set/clear them in ISR
2. on set, caching the injected vector number
3. on clear, invalidating the cache

The real purpose of this is enabling PV EOI which needs to quickly validate the vector. But non PV guests also benefit: with this patch, and without interrupt nesting, apic_find_highest_isr will always return immediately without scanning ISR.

Note on likely() usage in apic_find_highest_isr:
in my testing the cache was valid in >99% cases, so the annotation seems justified.

---
 arch/x86/kvm/lapic.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 arch/x86/kvm/lapic.h |  4 ++++
 2 files changed, 55 insertions(+), 2 deletions(-)
arch/x86/kvm/lapic.c +51 -2
index 93c1574..805d887 100644
@@ -107,6 +107,16 @@ static inline void apic_clear_vector(int vec, void *bitmap)
 	clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
 }
 
+static inline int __apic_test_and_set_vector(int vec, void *bitmap)
+{
+	return __test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
+static inline int __apic_test_and_clear_vector(int vec, void *bitmap)
+{
+	return __test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
 static inline int apic_hw_enabled(struct kvm_lapic *apic)
 {
 	return (apic)->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE;
@@ -210,6 +220,16 @@ static int find_highest_vector(void *bitmap)
 		return fls(word[word_offset << 2]) - 1 + (word_offset << 5);
 }
 
+static u8 count_vectors(void *bitmap)
+{
+	u32 *word = bitmap;
+	int word_offset;
+	u8 count = 0;
+	for (word_offset = 0; word_offset < MAX_APIC_VECTOR >> 5; ++word_offset)
+		count += hweight32(word[word_offset << 2]);
+	return count;
+}
+
 static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
 {
 	apic->irr_pending = true;
@@ -242,6 +262,27 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
 		apic->irr_pending = true;
 }
 
+static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
+{
+	if (!__apic_test_and_set_vector(vec, apic->regs + APIC_ISR))
+		++apic->isr_count;
+	BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
+	/*
+	 * ISR (in service register) bit is set when injecting an interrupt.
+	 * The highest vector is injected. Thus the latest bit set matches
+	 * the highest bit in ISR.
+	 */
+	apic->highest_isr_cache = vec;
+}
+
+static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
+{
+	if (__apic_test_and_clear_vector(vec, apic->regs + APIC_ISR))
+		--apic->isr_count;
+	BUG_ON(apic->isr_count < 0);
+	apic->highest_isr_cache = -1;
+}
+
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
 {
 	struct kvm_lapic *apic = vcpu->arch.apic;
@@ -273,6 +314,10 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq)
 static inline int apic_find_highest_isr(struct kvm_lapic *apic)
 {
 	int result;
+	if (!apic->isr_count)
+		return -1;
+	if (likely(apic->highest_isr_cache != -1))
+		return apic->highest_isr_cache;
 
 	result = find_highest_vector(apic->regs + APIC_ISR);
 	ASSERT(result == -1 || result >= 16);
@@ -492,7 +537,7 @@ static void apic_set_eoi(struct kvm_lapic *apic)
 	if (vector == -1)
 		return;
 
-	apic_clear_vector(vector, apic->regs + APIC_ISR);
+	apic_clear_isr(vector, apic);
 	apic_update_ppr(apic);
 
 	if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
@@ -1081,6 +1126,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
 		apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
 	}
 	apic->irr_pending = false;
+	apic->isr_count = 0;
+	apic->highest_isr_cache = -1;
 	update_divide_count(apic);
 	atomic_set(&apic->lapic_timer.pending, 0);
 	if (kvm_vcpu_is_bsp(vcpu))
@@ -1248,7 +1295,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
 	if (vector == -1)
 		return -1;
 
-	apic_set_vector(vector, apic->regs + APIC_ISR);
+	apic_set_isr(vector, apic);
 	apic_update_ppr(apic);
 	apic_clear_irr(vector, apic);
 	return vector;
@@ -1267,6 +1314,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
 	update_divide_count(apic);
 	start_apic_timer(apic);
 	apic->irr_pending = true;
+	apic->isr_count = count_vectors(apic->regs + APIC_ISR);
+	apic->highest_isr_cache = -1;
 	kvm_make_request(KVM_REQ_EVENT, vcpu);
 }
 
arch/x86/kvm/lapic.h +4 -0
index d29da25..5ac9e5e 100644
@@ -13,6 +13,10 @@ struct kvm_lapic {
 	u32 divide_count;
 	struct kvm_vcpu *vcpu;
 	bool irr_pending;
+	/* Number of bits set in ISR. */
+	s16 isr_count;
+	/* The highest vector set in ISR; if -1 - invalid, must scan ISR. */
+	int highest_isr_cache;
 	/**
 	 * APIC register page.  The layout matches the register layout seen by
 	 * the guest 1:1, because it is accessed by the vmx microcode.
Signature · 1 line
MST
#3 lore raw

PATCH v7 3/8 kvm_para: guest side for eoi avoidance

In reply to Michael S. Tsirkin

The idea is simple: there's a bit, per APIC, in guest memory, that tells the guest that it does not need EOI.
Guest tests it using a single est and clear operation - this is necessary so that host can detect interrupt nesting - and if set, it can skip the EOI MSR.

I run a simple microbenchmark to show exit reduction (note: for testing, need to apply follow-up patch 'kvm: host side for eoi optimization' + a qemu patch
I posted separately, on host):

Before:

Performance counter stats for 'sleep 1s':

            47,357 kvm:kvm_entry                                                [99.98%]
                 0 kvm:kvm_hypercall                                            [99.98%]
                 0 kvm:kvm_hv_hypercall                                         [99.98%]
             5,001 kvm:kvm_pio                                                  [99.98%]
                 0 kvm:kvm_cpuid                                                [99.98%]
            22,124 kvm:kvm_apic                                                 [99.98%]
            49,849 kvm:kvm_exit                                                 [99.98%]
            21,115 kvm:kvm_inj_virq                                             [99.98%]
                 0 kvm:kvm_inj_exception                                        [99.98%]
                 0 kvm:kvm_page_fault                                           [99.98%]
            22,937 kvm:kvm_msr                                                  [99.98%]
                 0 kvm:kvm_cr                                                   [99.98%]
                 0 kvm:kvm_pic_set_irq                                          [99.98%]
                 0 kvm:kvm_apic_ipi                                             [99.98%]
            22,207 kvm:kvm_apic_accept_irq                                      [99.98%]
            22,421 kvm:kvm_eoi                                                  [99.98%]
                 0 kvm:kvm_pv_eoi                                               [99.99%]
                 0 kvm:kvm_nested_vmrun                                         [99.99%]
                 0 kvm:kvm_nested_intercepts                                    [99.99%]
                 0 kvm:kvm_nested_vmexit                                        [99.99%]

0 kvm:kvm_nested_vmexit_inject [99.99%]
0 kvm:kvm_nested_intr_vmexit [99.99%]
0 kvm:kvm_invlpga [99.99%]
0 kvm:kvm_skinit [99.99%]
57 kvm:kvm_emulate_insn [99.99%]
0 kvm:vcpu_match_mmio [99.99%]
0 kvm:kvm_userspace_exit [99.99%]
2 kvm:kvm_set_irq [99.99%]
2 kvm:kvm_ioapic_set_irq [99.99%]
23,609 kvm:kvm_msi_set_irq [99.99%]
1 kvm:kvm_ack_irq [99.99%]
131 kvm:kvm_mmio [99.99%]
226 kvm:kvm_fpu [100.00%]
0 kvm:kvm_age_page [100.00%]
0 kvm:kvm_try_async_get_page [100.00%]
0 kvm:kvm_async_pf_doublefault [100.00%]
0 kvm:kvm_async_pf_not_present [100.00%]
0 kvm:kvm_async_pf_ready [100.00%]
0 kvm:kvm_async_pf_completed

1.002100578 seconds time elapsed

After:

Performance counter stats for 'sleep 1s':

            28,354 kvm:kvm_entry                                                [99.98%]
                 0 kvm:kvm_hypercall                                            [99.98%]
                 0 kvm:kvm_hv_hypercall                                         [99.98%]
             1,347 kvm:kvm_pio                                                  [99.98%]
                 0 kvm:kvm_cpuid                                                [99.98%]
             1,931 kvm:kvm_apic                                                 [99.98%]
            29,595 kvm:kvm_exit                                                 [99.98%]
            24,884 kvm:kvm_inj_virq                                             [99.98%]
                 0 kvm:kvm_inj_exception                                        [99.98%]
                 0 kvm:kvm_page_fault                                           [99.98%]
             1,986 kvm:kvm_msr                                                  [99.98%]
                 0 kvm:kvm_cr                                                   [99.98%]
                 0 kvm:kvm_pic_set_irq                                          [99.98%]
                 0 kvm:kvm_apic_ipi                                             [99.99%]
            25,953 kvm:kvm_apic_accept_irq                                      [99.99%]
            26,132 kvm:kvm_eoi                                                  [99.99%]
            26,593 kvm:kvm_pv_eoi                                               [99.99%]
                 0 kvm:kvm_nested_vmrun                                         [99.99%]
                 0 kvm:kvm_nested_intercepts                                    [99.99%]
                 0 kvm:kvm_nested_vmexit                                        [99.99%]

0 kvm:kvm_nested_vmexit_inject [99.99%]
0 kvm:kvm_nested_intr_vmexit [99.99%]
0 kvm:kvm_invlpga [99.99%]
0 kvm:kvm_skinit [99.99%]
284 kvm:kvm_emulate_insn [99.99%]
68 kvm:vcpu_match_mmio [99.99%]
68 kvm:kvm_userspace_exit [99.99%]
2 kvm:kvm_set_irq [99.99%]
2 kvm:kvm_ioapic_set_irq [99.99%]
28,288 kvm:kvm_msi_set_irq [99.99%]
1 kvm:kvm_ack_irq [99.99%]
131 kvm:kvm_mmio [100.00%]
588 kvm:kvm_fpu [100.00%]
0 kvm:kvm_age_page [100.00%]
0 kvm:kvm_try_async_get_page [100.00%]
0 kvm:kvm_async_pf_doublefault [100.00%]
0 kvm:kvm_async_pf_not_present [100.00%]
0 kvm:kvm_async_pf_ready [100.00%]
0 kvm:kvm_async_pf_completed

1.002039622 seconds time elapsed

We see that # of exits is almost halved.

---
 arch/x86/include/asm/bitops.h   |  6 +++--
 arch/x86/include/asm/kvm_para.h |  7 ++++++
 arch/x86/kernel/kvm.c           | 51 ++++++++++++++++++++++++++++++++++++++---
 3 files changed, 59 insertions(+), 5 deletions(-)
arch/x86/include/asm/bitops.h +4 -2
index a6983b2..47f9eff 100644
@@ -28,11 +28,13 @@
 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
 /* Technically wrong, but this avoids compilation errors on some gcc
    versions. */
-#define BITOP_ADDR(x) "=m" (*(volatile long *) (x))
+#define BITOP_ADDR_CONSTRAINT "=m"
 #else
-#define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
+#define BITOP_ADDR_CONSTRAINT "+m"
 #endif
 
+#define BITOP_ADDR(x) BITOP_ADDR_CONSTRAINT (*(volatile long *) (x))
+
 #define ADDR				BITOP_ADDR(addr)
 
 /*
arch/x86/include/asm/kvm_para.h +7 -0
index 63ab166..2f7712e 100644
@@ -22,6 +22,7 @@
 #define KVM_FEATURE_CLOCKSOURCE2        3
 #define KVM_FEATURE_ASYNC_PF		4
 #define KVM_FEATURE_STEAL_TIME		5
+#define KVM_FEATURE_PV_EOI		6
 
 /* The last 8 bits are used to indicate how to interpret the flags field
  * in pvclock structure. If no bits are set, all flags are ignored.
@@ -37,6 +38,7 @@
 #define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01
 #define MSR_KVM_ASYNC_PF_EN 0x4b564d02
 #define MSR_KVM_STEAL_TIME  0x4b564d03
+#define MSR_KVM_PV_EOI_EN      0x4b564d04
 
 struct kvm_steal_time {
 	__u64 steal;
@@ -89,6 +91,11 @@ struct kvm_vcpu_pv_apf_data {
 	__u32 enabled;
 };
 
+#define KVM_PV_EOI_BIT 0
+#define KVM_PV_EOI_MASK (0x1 << KVM_PV_EOI_BIT)
+#define KVM_PV_EOI_ENABLED KVM_PV_EOI_MASK
+#define KVM_PV_EOI_DISABLED 0x0
+
 #ifdef __KERNEL__
 #include <asm/processor.h>
 
arch/x86/kernel/kvm.c +48 -3

95 lines not on this page · raw message

Signature · 1 line
MST
#4 lore raw

Re: [PATCHv7 3/8] kvm_para: guest side for eoi avoidance

Quoted 20 lines · Michael S. Tsirkin

The idea is simple: there's a bit, per APIC, in guest memory, that tells the guest that it does not need EOI.
Guest tests it using a single est and clear operation - this is necessary so that host can detect interrupt nesting - and if set, it can skip the EOI MSR.

I run a simple microbenchmark to show exit reduction (note: for testing, need to apply follow-up patch 'kvm: host side for eoi optimization' + a qemu patch
I posted separately, on host):

arch/x86/include/asm/bitops.h +0 -0
index a6983b2..47f9eff 100644
@@ -28,11 +28,13 @@
 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
 /* Technically wrong, but this avoids compilation errors on some gcc
    versions. */

arch/x86/include/asm/bitops.h line 38

Quoted 10 lines
arch/x86/include/asm/bitops.h +4 -2
-#define BITOP_ADDR(x) "=m" (*(volatile long *) (x))
+#define BITOP_ADDR_CONSTRAINT "=m"
 #else
-#define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
+#define BITOP_ADDR_CONSTRAINT "+m"
 #endif
 
+#define BITOP_ADDR(x) BITOP_ADDR_CONSTRAINT (*(volatile long *) (x))
+
 #define ADDR				BITOP_ADDR(addr)

What's this doing here?

arch/x86/include/asm/bitops.h

Quoted 4 lines
arch/x86/include/asm/bitops.h +3 -0
+/* size alignment is implied but just to make it explicit. */
+static DEFINE_PER_CPU(unsigned long, kvm_apic_eoi) __aligned(2) =
+	KVM_PV_EOI_DISABLED;

You're actually breaking the alignment. ulong has 8 byte alignment sometimes and you can make it cross cache boundary this way.

arch/x86/include/asm/bitops.h void __cpuinit kvm_guest_cpu_init(void) · line 326

Quoted 12 lines
arch/x86/include/asm/bitops.h +5 -0
+
 void __cpuinit kvm_guest_cpu_init(void)
 {
 	if (!kvm_para_available())
@@ -300,11 +320,17 @@ void __cpuinit kvm_guest_cpu_init(void)
 		       smp_processor_id());
 	}
 
+	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) {
+		__get_cpu_var(kvm_apic_eoi) = 0;
+		wrmsrl(MSR_KVM_PV_EOI_EN, __pa(&__get_cpu_var(kvm_apic_eoi)) |
+		       KVM_MSR_ENABLED);

Bad formatting.

arch/x86/include/asm/bitops.h void __cpuinit kvm_guest_cpu_init(void) · line 332

Quoted 6 lines
arch/x86/include/asm/bitops.h +2 -0
+	}
+
 	if (has_steal_clock)
 		kvm_register_steal_time();
 }
 

Please check that the kexec path also disables pveoi.

Signature · 1 line
error compiling committee.c: too many arguments to function
#5 lore raw

Re: [PATCHv7 3/8] kvm_para: guest side for eoi avoidance

Quoted 28 lines · Avi Kivity
Quoted 27 lines · Michael S. Tsirkin

The idea is simple: there's a bit, per APIC, in guest memory, that tells the guest that it does not need EOI.
Guest tests it using a single est and clear operation - this is necessary so that host can detect interrupt nesting - and if set, it can skip the EOI MSR.

I run a simple microbenchmark to show exit reduction (note: for testing, need to apply follow-up patch 'kvm: host side for eoi optimization' + a qemu patch
I posted separately, on host):

arch/x86/include/asm/bitops.h +2 -2
index a6983b2..47f9eff 100644
@@ -28,11 +28,13 @@
 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
 /* Technically wrong, but this avoids compilation errors on some gcc
    versions. */
-#define BITOP_ADDR(x) "=m" (*(volatile long *) (x))
+#define BITOP_ADDR_CONSTRAINT "=m"
 #else
-#define BITOP_ADDR(x) "+m" (*(volatile long *) (x))
+#define BITOP_ADDR_CONSTRAINT "+m"
 #endif
 
Quoted 5 lines

arch/x86/include/asm/bitops.h line 38

Quoted 3 lines
arch/x86/include/asm/bitops.h +2 -0
+#define BITOP_ADDR(x) BITOP_ADDR_CONSTRAINT (*(volatile long *) (x))
+
 #define ADDR				BITOP_ADDR(addr)

What's this doing here?

Ugh. More leftovers from when I had inline asm here. Will remove.

Quoted 7 lines

arch/x86/include/asm/bitops.h

Quoted 4 lines
arch/x86/include/asm/bitops.h +3 -0
+/* size alignment is implied but just to make it explicit. */
+static DEFINE_PER_CPU(unsigned long, kvm_apic_eoi) __aligned(2) =
+	KVM_PV_EOI_DISABLED;

You're actually breaking the alignment. ulong has 8 byte alignment sometimes and you can make it cross cache boundary this way.

No, if you look at the definition of __aligned
you will see that it limits the alignment from below. Compiler still applies the natural size alignment.
You are not the first to get confused. So I wonder: is it better to add a comment or simply remove __aligned here.

Quoted 8 lines
Quoted 8 lines
arch/x86/include/asm/bitops.h +1 -0
+
 void __cpuinit kvm_guest_cpu_init(void)
 {
 	if (!kvm_para_available())
@@ -300,11 +320,17 @@ void __cpuinit kvm_guest_cpu_init(void)
 		       smp_processor_id());
 	}
 
Quoted 6 lines

arch/x86/include/asm/bitops.h void __cpuinit kvm_guest_cpu_init(void) · line 326

Quoted 4 lines
arch/x86/include/asm/bitops.h +4 -0
+	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) {
+		__get_cpu_var(kvm_apic_eoi) = 0;
+		wrmsrl(MSR_KVM_PV_EOI_EN, __pa(&__get_cpu_var(kvm_apic_eoi)) |
+		       KVM_MSR_ENABLED);

Bad formatting.

I guess temporary will make it prettier.

	unsigned long pa;
	__get_cpu_var(kvm_apic_eoi) = 0;
	pa = __pa(&__get_cpu_var(kvm_apic_eoi)) | KVM_MSR_ENABLED;
	wrmsrl(MSR_KVM_PV_EOI_EN, pa);

or did I miss the point?

Quoted 9 lines

arch/x86/include/asm/bitops.h void __cpuinit kvm_guest_cpu_init(void) · line 332

Quoted 6 lines
arch/x86/include/asm/bitops.h +2 -0
+	}
+
 	if (has_steal_clock)
 		kvm_register_steal_time();
 }
 

Please check that the kexec path also disables pveoi.

The chunk in kvm_pv_guest_cpu_reboot does this, doesn't it?

Quoted 3 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
#6 lore raw

Re: [PATCHv7 3/8] kvm_para: guest side for eoi avoidance

Quoted 9 lines · Michael S. Tsirkin
Quoted 8 lines

arch/x86/kernel/kvm.c static void kvm_register_steal_time(void) · line 290

Quoted 5 lines
arch/x86/kernel/kvm.c +3 -0
+/* size alignment is implied but just to make it explicit. */
+static DEFINE_PER_CPU(unsigned long, kvm_apic_eoi) __aligned(2) =
+	KVM_PV_EOI_DISABLED;

You're actually breaking the alignment. ulong has 8 byte alignment sometimes and you can make it cross cache boundary this way.

Quoted 5 lines

No, if you look at the definition of __aligned
you will see that it limits the alignment from below. Compiler still applies the natural size alignment.
You are not the first to get confused. So I wonder: is it better to add a comment or simply remove __aligned here.

Both.

Quoted 8 lines
Quoted 7 lines

arch/x86/kernel/kvm.c void __cpuinit kvm_guest_cpu_init(void) · line 326

Quoted 5 lines
arch/x86/kernel/kvm.c +4 -0
+	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) {
+		__get_cpu_var(kvm_apic_eoi) = 0;
+		wrmsrl(MSR_KVM_PV_EOI_EN, __pa(&__get_cpu_var(kvm_apic_eoi)) |
+		       KVM_MSR_ENABLED);

Bad formatting.

Quoted 5 lines

I guess temporary will make it prettier.

	unsigned long pa;
	__get_cpu_var(kvm_apic_eoi) = 0;
	pa = __pa(&__get_cpu_var(kvm_apic_eoi)) | KVM_MSR_ENABLED;
	wrmsrl(MSR_KVM_PV_EOI_EN, pa);

That, or

+ wrmsrl(MSR_KVM_PV_EOI_EN,
+ __pa(&__get_cpu_var(kvm_apic_eoi)) | _ENABLED);

You have an argument split over two lines with no helpful indentation to show this.

Quoted 5 lines
Quoted 3 lines

Please check that the kexec path also disables pveoi.

The chunk in kvm_pv_guest_cpu_reboot does this, doesn't it?

Dunno, does it?

Signature · 1 line
error compiling committee.c: too many arguments to function
#7 lore raw

Re: [PATCHv7 3/8] kvm_para: guest side for eoi avoidance

Quoted 10 lines · Avi Kivity
Quoted 9 lines · Michael S. Tsirkin
Quoted 8 lines

arch/x86/kernel/kvm.c static void kvm_register_steal_time(void) · line 290

Quoted 5 lines
arch/x86/kernel/kvm.c +3 -0
+/* size alignment is implied but just to make it explicit. */
+static DEFINE_PER_CPU(unsigned long, kvm_apic_eoi) __aligned(2) =
+	KVM_PV_EOI_DISABLED;

You're actually breaking the alignment. ulong has 8 byte alignment sometimes and you can make it cross cache boundary this way.

Quoted 7 lines
Quoted 5 lines

No, if you look at the definition of __aligned
you will see that it limits the alignment from below. Compiler still applies the natural size alignment.
You are not the first to get confused. So I wonder: is it better to add a comment or simply remove __aligned here.

Both.

Will do.

Quoted 24 lines
Quoted 8 lines
Quoted 7 lines

arch/x86/kernel/kvm.c void __cpuinit kvm_guest_cpu_init(void) · line 326

Quoted 5 lines
arch/x86/kernel/kvm.c +4 -0
+	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) {
+		__get_cpu_var(kvm_apic_eoi) = 0;
+		wrmsrl(MSR_KVM_PV_EOI_EN, __pa(&__get_cpu_var(kvm_apic_eoi)) |
+		       KVM_MSR_ENABLED);

Bad formatting.

Quoted 5 lines

I guess temporary will make it prettier.

	unsigned long pa;
	__get_cpu_var(kvm_apic_eoi) = 0;
	pa = __pa(&__get_cpu_var(kvm_apic_eoi)) | KVM_MSR_ENABLED;
	wrmsrl(MSR_KVM_PV_EOI_EN, pa);

That, or

(quoted diff) +2 -0
+		wrmsrl(MSR_KVM_PV_EOI_EN,
+                      __pa(&__get_cpu_var(kvm_apic_eoi)) | _ENABLED);

You have an argument split over two lines with no helpful indentation to show this.

Quoted 2 lines
Quoted 2 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Please check that the kexec path also disables pveoi.

The chunk in kvm_pv_guest_cpu_reboot does this, doesn't it?

Dunno, does it?

I thought it absolutely does but now I noticed this:

Without CONFIG_KEXEC_JUMP, it calls kernel_restart_prepare which invokes notifiers. So fine.
But with CONFIG_KEXEC_JUMP it does suspend which is way more complex - it stops all other cpus so we are fine but still not sure about the last one.

Any idea?

How does it work for e.g. ASYNC_PF?

Quoted 5 lines
Signature · 2 lines
-- 
error compiling committee.c: too many arguments to function
#8 lore raw

PATCH v7 4/8 x86/bitops: note on __test_and_clear_bit atomicity

In reply to Michael S. Tsirkin

__test_and_clear_bit is actually atomic with respect to the local CPU. Add a note saying that KVM on x86 relies on this behaviour so people don't accidentaly break it. Also warn not to rely on this in portable code.

---
 arch/x86/include/asm/bitops.h | 7 +++++++
 1 file changed, 7 insertions(+)
arch/x86/include/asm/bitops.h +7 -0
index 47f9eff..75e3787 100644
@@ -266,6 +266,13 @@ static inline int test_and_clear_bit(int nr, volatile unsigned long *addr)
  * This operation is non-atomic and can be reordered.
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
+ *
+ * Note: the operation is performed atomically with respect to
+ * the local CPU, but not other CPUs. Portable code should not
+ * rely on this behaviour.
+ * KVM relies on this behaviour on x86 for modifying memory that is also
+ * accessed from a hypervisor on the same CPU if running in a VM: don't change
+ * this without also updating arch/x86/kernel/kvm.c
  */
 static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
 {
Signature · 1 line
MST
#9 lore raw

PATCH v7 5/8 kvm: eoi msi documentation

In reply to Michael S. Tsirkin

Document the new EOI MSR. Couldn't decide whether this change belongs conceptually on guest or host side, so a separate patch.

---
 Documentation/virtual/kvm/msr.txt | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
Documentation/virtual/kvm/msr.txt +32 -0
index 96b41bd..6ae5a85 100644
@@ -223,3 +223,35 @@ MSR_KVM_STEAL_TIME: 0x4b564d03
 		steal: the amount of time in which this vCPU did not run, in
 		nanoseconds. Time during which the vcpu is idle, will not be
 		reported as steal time.
+
+MSR_KVM_EOI_EN: 0x4b564d04
+	data: Bit 0 is 1 when PV end of interrupt is enabled on the vcpu; 0
+	when disabled.  When enabled, bits 63-1 hold 2-byte aligned physical address
+	of a 2 byte memory area which must be in guest RAM and must be zeroed.
+
+	The first, least significant bit of 2 byte memory location will be
+	written to by the hypervisor, typically at the time of interrupt
+	injection.  Value of 1 means that guest can skip writing EOI to the apic
+	(using MSR or MMIO write); instead, it is sufficient to signal
+	EOI by clearing the bit in guest memory - this location will
+	later be polled by the hypervisor.
+	Value of 0 means that the EOI write is required.
+
+	It is always safe for the guest to ignore the optimization and perform
+	the APIC EOI write anyway.
+
+	Hypervisor is guaranteed to only modify this least
+	significant bit while in the current VCPU context, this means that
+	guest does not need to use either lock prefix or memory ordering
+	primitives to synchronise with the hypervisor.
+
+	However, hypervisor can set and clear this memory bit at any time:
+	therefore to make sure hypervisor does not interrupt the
+	guest and clear the least significant bit in the memory area
+	in the window between guest testing it to detect
+	whether it can skip EOI apic write and between guest
+	clearing it to signal EOI to the hypervisor,
+	guest must both read the least significant bit in the memory area and
+	clear it using a single CPU instruction, such as test and clear, or
+	compare and exchange.
+
Signature · 1 line
MST
#10 lore raw

Re: [PATCHv7 5/8] kvm: eoi msi documentation

Quoted 13 lines · Michael S. Tsirkin

Document the new EOI MSR. Couldn't decide whether this change belongs conceptually on guest or host side, so a separate patch.

---
 Documentation/virtual/kvm/msr.txt | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
Documentation/virtual/kvm/msr.txt +0 -0
index 96b41bd..6ae5a85 100644

Documentation/virtual/kvm/msr.txt MSR_KVM_STEAL_TIME: 0x4b564d03 · line 230

Quoted 8 lines
Documentation/virtual/kvm/msr.txt +5 -0
@@ -223,3 +223,35 @@ MSR_KVM_STEAL_TIME: 0x4b564d03
 		steal: the amount of time in which this vCPU did not run, in
 		nanoseconds. Time during which the vcpu is idle, will not be
 		reported as steal time.
+
+MSR_KVM_EOI_EN: 0x4b564d04
+	data: Bit 0 is 1 when PV end of interrupt is enabled on the vcpu; 0
+	when disabled.  When enabled, bits 63-1 hold 2-byte aligned physical address
+	of a 2 byte memory area which must be in guest RAM and must be zeroed.

2 byte aligned means we must never access it on the host with a >2 byte instruction, or we risk touching unmapped memory.

Signature · 1 line
error compiling committee.c: too many arguments to function
#11 lore raw

Re: [PATCHv7 5/8] kvm: eoi msi documentation

Quoted 9 lines · Avi Kivity
Quoted 8 lines · Michael S. Tsirkin

Document the new EOI MSR. Couldn't decide whether this change belongs conceptually on guest or host side, so a separate patch.

---
 Documentation/virtual/kvm/msr.txt | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
Quoted 16 lines

Documentation/virtual/kvm/msr.txt MSR_KVM_STEAL_TIME: 0x4b564d03 · line 230

Quoted 13 lines
Documentation/virtual/kvm/msr.txt +5 -0
index 96b41bd..6ae5a85 100644
@@ -223,3 +223,35 @@ MSR_KVM_STEAL_TIME: 0x4b564d03
 		steal: the amount of time in which this vCPU did not run, in
 		nanoseconds. Time during which the vcpu is idle, will not be
 		reported as steal time.
+
+MSR_KVM_EOI_EN: 0x4b564d04
+	data: Bit 0 is 1 when PV end of interrupt is enabled on the vcpu; 0
+	when disabled.  When enabled, bits 63-1 hold 2-byte aligned physical address
+	of a 2 byte memory area which must be in guest RAM and must be zeroed.

2 byte aligned means we must never access it on the host with a >2 byte instruction, or we risk touching unmapped memory.

Yes. So ... that's correct for any length.
The patch actually accesses a single byte only.

Could you clarify what you are saying here please?

Quoted 3 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
#12 lore raw

Re: [PATCHv7 5/8] kvm: eoi msi documentation

Quoted 27 lines · Michael S. Tsirkin
Quoted 9 lines · Avi Kivity
Quoted 8 lines · Michael S. Tsirkin

Document the new EOI MSR. Couldn't decide whether this change belongs conceptually on guest or host side, so a separate patch.

---
 Documentation/virtual/kvm/msr.txt | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
Quoted 16 lines

Documentation/virtual/kvm/msr.txt MSR_KVM_STEAL_TIME: 0x4b564d03 · line 230

Quoted 13 lines
Documentation/virtual/kvm/msr.txt +5 -0
index 96b41bd..6ae5a85 100644
@@ -223,3 +223,35 @@ MSR_KVM_STEAL_TIME: 0x4b564d03
 		steal: the amount of time in which this vCPU did not run, in
 		nanoseconds. Time during which the vcpu is idle, will not be
 		reported as steal time.
+
+MSR_KVM_EOI_EN: 0x4b564d04
+	data: Bit 0 is 1 when PV end of interrupt is enabled on the vcpu; 0
+	when disabled.  When enabled, bits 63-1 hold 2-byte aligned physical address
+	of a 2 byte memory area which must be in guest RAM and must be zeroed.

2 byte aligned means we must never access it on the host with a >2 byte instruction, or we risk touching unmapped memory.

Quoted 5 lines

Yes. So ... that's correct for any length.
The patch actually accesses a single byte only.

Could you clarify what you are saying here please?

It means, if we want to use __set_bit() (and if __set_bit wants to access this as a long) then we can get an exception.

The spec shouldn't limit us in this way, even if the implementation is okay.

Signature · 1 line
error compiling committee.c: too many arguments to function
#13 lore raw

Re: [PATCHv7 5/8] kvm: eoi msi documentation

Quoted 28 lines · Avi Kivity
Quoted 27 lines · Michael S. Tsirkin
Quoted 25 lines · Avi Kivity
Quoted 13 lines · Michael S. Tsirkin

Document the new EOI MSR. Couldn't decide whether this change belongs conceptually on guest or host side, so a separate patch.

---
 Documentation/virtual/kvm/msr.txt | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
Documentation/virtual/kvm/msr.txt +0 -0
index 96b41bd..6ae5a85 100644

Documentation/virtual/kvm/msr.txt MSR_KVM_STEAL_TIME: 0x4b564d03 · line 230

Quoted 8 lines
Documentation/virtual/kvm/msr.txt +5 -0
@@ -223,3 +223,35 @@ MSR_KVM_STEAL_TIME: 0x4b564d03
 		steal: the amount of time in which this vCPU did not run, in
 		nanoseconds. Time during which the vcpu is idle, will not be
 		reported as steal time.
+
+MSR_KVM_EOI_EN: 0x4b564d04
+	data: Bit 0 is 1 when PV end of interrupt is enabled on the vcpu; 0
+	when disabled.  When enabled, bits 63-1 hold 2-byte aligned physical address
+	of a 2 byte memory area which must be in guest RAM and must be zeroed.

2 byte aligned means we must never access it on the host with a >2 byte instruction, or we risk touching unmapped memory.

Quoted 8 lines
Quoted 5 lines

Yes. So ... that's correct for any length.
The patch actually accesses a single byte only.

Could you clarify what you are saying here please?

It means, if we want to use __set_bit() (and if __set_bit wants to access this as a long) then we can get an exception.

We can't use __set_bit. It's in guest memory.

Quoted 1 line

The spec shouldn't limit us in this way, even if the implementation is okay.

This specific spec seems to create the smallest possible amount of work for the hypervisor. You have an idea for an interface that will make the hypervisor side even more compact? Can you clarify?

Quoted 3 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
#14 lore raw

Re: [PATCHv7 5/8] kvm: eoi msi documentation

In reply to Avi Kivity
Quoted 9 lines · Avi Kivity
Quoted 8 lines · Michael S. Tsirkin

Document the new EOI MSR. Couldn't decide whether this change belongs conceptually on guest or host side, so a separate patch.

---
 Documentation/virtual/kvm/msr.txt | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
Quoted 16 lines

Documentation/virtual/kvm/msr.txt MSR_KVM_STEAL_TIME: 0x4b564d03 · line 230

Quoted 13 lines
Documentation/virtual/kvm/msr.txt +5 -0
index 96b41bd..6ae5a85 100644
@@ -223,3 +223,35 @@ MSR_KVM_STEAL_TIME: 0x4b564d03
 		steal: the amount of time in which this vCPU did not run, in
 		nanoseconds. Time during which the vcpu is idle, will not be
 		reported as steal time.
+
+MSR_KVM_EOI_EN: 0x4b564d04
+	data: Bit 0 is 1 when PV end of interrupt is enabled on the vcpu; 0
+	when disabled.  When enabled, bits 63-1 hold 2-byte aligned physical address
+	of a 2 byte memory area which must be in guest RAM and must be zeroed.

2 byte aligned means we must never access it on the host with a >2 byte instruction, or we risk touching unmapped memory.

Wait, maybe you mean the text above should go into documentation?

Quoted 3 lines
Signature · 1 line
error compiling committee.c: too many arguments to function
#15 lore raw

PATCH v7 6/8 kvm: only sync when attention bits set

In reply to Michael S. Tsirkin

Commit eb0dc6d0368072236dcd086d7fdc17fd3c4574d4 introduced apic attention bitmask but kvm still syncs lapic unconditionally. As that commit suggested and in anticipation of adding more attention bits, only sync lapic if(apic_attention).

---
 arch/x86/kvm/x86.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/kvm/x86.c +2 -1
index be6d549..4e582c0 100644
@@ -5388,7 +5388,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 	if (unlikely(vcpu->arch.tsc_always_catchup))
 		kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
 
-	kvm_lapic_sync_from_vapic(vcpu);
+	if (vcpu->arch.apic_attention)
+		kvm_lapic_sync_from_vapic(vcpu);
 
 	r = kvm_x86_ops->handle_exit(vcpu);
 out:
Signature · 1 line
MST
#16 lore raw

PATCH v7 7/8 kvm: rearrange injection cancelling code

In reply to Michael S. Tsirkin

Each time we need to cancel injection we invoke same code (cancel_injection callback). Move it towards the end of function using the familiar goto on error pattern.

Will make it easier to do more cleanups for PV EOI.

---
 arch/x86/kvm/x86.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kvm/x86.c +6 -4
index 4e582c0..cb19d3b 100644
@@ -5296,8 +5296,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
 	r = kvm_mmu_reload(vcpu);
 	if (unlikely(r)) {
-		kvm_x86_ops->cancel_injection(vcpu);
-		goto out;
+		goto cancel_injection;
 	}
 
 	preempt_disable();
@@ -5322,9 +5321,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 		smp_wmb();
 		local_irq_enable();
 		preempt_enable();
-		kvm_x86_ops->cancel_injection(vcpu);
 		r = 1;
-		goto out;
+		goto cancel_injection;
 	}
 
 	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
@@ -5392,6 +5390,10 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 		kvm_lapic_sync_from_vapic(vcpu);
 
 	r = kvm_x86_ops->handle_exit(vcpu);
+	return r;
+
+cancel_injection:
+	kvm_x86_ops->cancel_injection(vcpu);
 out:
 	return r;
 }
Signature · 1 line
MST
#17 lore raw

PATCH v7 8/8 kvm: host side for eoi optimization

In reply to Michael S. Tsirkin

Implementation of PV EOI using shared memory.
This reduces the number of exits an interrupt
causes as much as by half.

The idea is simple: there's a bit, per APIC, in guest memory, that tells the guest that it does not need EOI.
We set it before injecting an interrupt and clear before injecting a nested one. Guest tests it using a test and clear operation - this is necessary
so that host can detect interrupt nesting -
and if set, it can skip the EOI MSR.

There's a new MSR to set the address of said register in guest memory. Otherwise not much changed:
- Guest EOI is not required
- Register is tested & ISR is automatically cleared on exit

For testing results see description of previous patch 'kvm_para: guest side for eoi avoidance'.

---
 arch/x86/include/asm/kvm_host.h |  12 ++++
 arch/x86/kvm/cpuid.c            |   1 +
 arch/x86/kvm/lapic.c            | 140 ++++++++++++++++++++++++++++++++++++++--
 arch/x86/kvm/lapic.h            |   2 +
 arch/x86/kvm/trace.h            |  34 ++++++++++
 arch/x86/kvm/x86.c              |   7 ++
 6 files changed, 192 insertions(+), 4 deletions(-)
arch/x86/include/asm/kvm_host.h +12 -0
index db7c1f2..dfc066c 100644
@@ -175,6 +175,13 @@ enum {
 
 /* apic attention bits */
 #define KVM_APIC_CHECK_VAPIC	0
+/*
+ * The following bit is set with PV-EOI, unset on EOI.
+ * We detect PV-EOI changes by guest by comparing
+ * this bit with PV-EOI in guest memory.
+ * See the implementation in apic_update_pv_eoi.
+ */ 
+#define KVM_APIC_PV_EOI_PENDING	1
 
 /*
  * We don't want allocation failures within the mmu code, so we preallocate
@@ -484,6 +491,11 @@ struct kvm_vcpu_arch {
 		u64 length;
 		u64 status;
 	} osvw;
+
+	struct {
+		u64 msr_val;
+		struct gfn_to_hva_cache data;
+	} pv_eoi;
 };
 
 struct kvm_lpage_info {
arch/x86/kvm/cpuid.c +1 -0
index 7df1c6d..61ccbdf 100644
@@ -409,6 +409,7 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
 			     (1 << KVM_FEATURE_NOP_IO_DELAY) |
 			     (1 << KVM_FEATURE_CLOCKSOURCE2) |
 			     (1 << KVM_FEATURE_ASYNC_PF) |
+			     (1 << KVM_FEATURE_PV_EOI) |
 			     (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
 
 		if (sched_info_on())
arch/x86/kvm/lapic.c +136 -4

200 lines not on this page · raw message

arch/x86/kvm/lapic.h +2 -0
index 5ac9e5e..4af5405 100644
@@ -69,4 +69,6 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu)
 {
 	return vcpu->arch.hv_vapic & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE;
 }
+
+int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data);
 #endif
arch/x86/kvm/trace.h +34 -0
index 911d264..851914e 100644
@@ -517,6 +517,40 @@ TRACE_EVENT(kvm_apic_accept_irq,
 		  __entry->coalesced ? " (coalesced)" : "")
 );
 
+TRACE_EVENT(kvm_eoi,
+	    TP_PROTO(struct kvm_lapic *apic, int vector),
+	    TP_ARGS(apic, vector),
+
+	TP_STRUCT__entry(
+		__field(	__u32,		apicid		)
+		__field(	int,		vector		)
+	),
+
+	TP_fast_assign(
+		__entry->apicid		= apic->vcpu->vcpu_id;
+		__entry->vector		= vector;
+	),
+
+	TP_printk("apicid %x vector %d", __entry->apicid, __entry->vector)
+);
+
+TRACE_EVENT(kvm_pv_eoi,
+	    TP_PROTO(struct kvm_lapic *apic, int vector),
+	    TP_ARGS(apic, vector),
+
+	TP_STRUCT__entry(
+		__field(	__u32,		apicid		)
+		__field(	int,		vector		)
+	),
+
+	TP_fast_assign(
+		__entry->apicid		= apic->vcpu->vcpu_id;
+		__entry->vector		= vector;
+	),
+
+	TP_printk("apicid %x vector %d", __entry->apicid, __entry->vector)
+);
+
 /*
  * Tracepoint for nested VMRUN
  */
arch/x86/kvm/x86.c +7 -0
index cb19d3b..3913fb1 100644
@@ -795,6 +795,7 @@ static u32 msrs_to_save[] = {
 	MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
 	HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL,
 	HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
+	MSR_KVM_PV_EOI_EN,
 	MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
 	MSR_STAR,
 #ifdef CONFIG_X86_64
@@ -1653,6 +1654,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 		kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu);
 
 		break;
+	case MSR_KVM_PV_EOI_EN:
+		if (kvm_lapic_enable_pv_eoi(vcpu, data))
+			return 1;
+		break;
 
 	case MSR_IA32_MCG_CTL:
 	case MSR_IA32_MCG_STATUS:
@@ -5394,6 +5399,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
 cancel_injection:
 	kvm_x86_ops->cancel_injection(vcpu);
+	if (unlikely(vcpu->arch.apic_attention))
+		kvm_lapic_sync_from_vapic(vcpu);
 out:
 	return r;
 }
Signature · 1 line
MST