Skip to content

Commit 892e7b8

Browse files
committed
Merge tag 'kvm-x86-vmx-6.14' of https://github.com/kvm-x86/linux into HEAD
KVM VMX changes for 6.14: - Fix a bug where KVM updates hardware's APICv cache of the highest ISR bit while L2 is active, while ultimately results in a hardware-accelerated L1 EOI effectively being lost. - Honor event priority when emulating Posted Interrupt delivery during nested VM-Enter by queueing KVM_REQ_EVENT instead of immediately handling the interrupt. - Drop kvm_x86_ops.hwapic_irr_update() as KVM updates hardware's APICv cache prior to every VM-Enter. - Rework KVM's processing of the Page-Modification Logging buffer to reap entries in the same order they were created, i.e. to mark gfns dirty in the same order that hardware marked the page/PTE dirty. - Misc cleanups.
2 parents 672162a + 37c3ddf commit 892e7b8

File tree

9 files changed

+120
-82
lines changed

9 files changed

+120
-82
lines changed

arch/x86/include/asm/kvm-x86-ops.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ KVM_X86_OP(enable_nmi_window)
8383
KVM_X86_OP(enable_irq_window)
8484
KVM_X86_OP_OPTIONAL(update_cr8_intercept)
8585
KVM_X86_OP(refresh_apicv_exec_ctrl)
86-
KVM_X86_OP_OPTIONAL(hwapic_irr_update)
8786
KVM_X86_OP_OPTIONAL(hwapic_isr_update)
8887
KVM_X86_OP_OPTIONAL(load_eoi_exitmap)
8988
KVM_X86_OP_OPTIONAL(set_virtual_apic_mode)

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,8 +1734,7 @@ struct kvm_x86_ops {
17341734
const unsigned long required_apicv_inhibits;
17351735
bool allow_apicv_in_x2apic_without_x2apic_virtualization;
17361736
void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
1737-
void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
1738-
void (*hwapic_isr_update)(int isr);
1737+
void (*hwapic_isr_update)(struct kvm_vcpu *vcpu, int isr);
17391738
void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
17401739
void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu);
17411740
void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu);

arch/x86/kvm/lapic.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -734,10 +734,7 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)
734734
static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
735735
{
736736
if (unlikely(apic->apicv_active)) {
737-
/* need to update RVI */
738737
kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR);
739-
kvm_x86_call(hwapic_irr_update)(apic->vcpu,
740-
apic_find_highest_irr(apic));
741738
} else {
742739
apic->irr_pending = false;
743740
kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR);
@@ -763,7 +760,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
763760
* just set SVI.
764761
*/
765762
if (unlikely(apic->apicv_active))
766-
kvm_x86_call(hwapic_isr_update)(vec);
763+
kvm_x86_call(hwapic_isr_update)(apic->vcpu, vec);
767764
else {
768765
++apic->isr_count;
769766
BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
@@ -808,14 +805,25 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
808805
* and must be left alone.
809806
*/
810807
if (unlikely(apic->apicv_active))
811-
kvm_x86_call(hwapic_isr_update)(apic_find_highest_isr(apic));
808+
kvm_x86_call(hwapic_isr_update)(apic->vcpu, apic_find_highest_isr(apic));
812809
else {
813810
--apic->isr_count;
814811
BUG_ON(apic->isr_count < 0);
815812
apic->highest_isr_cache = -1;
816813
}
817814
}
818815

816+
void kvm_apic_update_hwapic_isr(struct kvm_vcpu *vcpu)
817+
{
818+
struct kvm_lapic *apic = vcpu->arch.apic;
819+
820+
if (WARN_ON_ONCE(!lapic_in_kernel(vcpu)) || !apic->apicv_active)
821+
return;
822+
823+
kvm_x86_call(hwapic_isr_update)(vcpu, apic_find_highest_isr(apic));
824+
}
825+
EXPORT_SYMBOL_GPL(kvm_apic_update_hwapic_isr);
826+
819827
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
820828
{
821829
/* This may race with setting of irr in __apic_accept_irq() and
@@ -2805,8 +2813,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
28052813
apic_update_ppr(apic);
28062814
if (apic->apicv_active) {
28072815
kvm_x86_call(apicv_post_state_restore)(vcpu);
2808-
kvm_x86_call(hwapic_irr_update)(vcpu, -1);
2809-
kvm_x86_call(hwapic_isr_update)(-1);
2816+
kvm_x86_call(hwapic_isr_update)(vcpu, -1);
28102817
}
28112818

28122819
vcpu->arch.apic_arb_prio = 0;
@@ -3121,9 +3128,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
31213128
kvm_apic_update_apicv(vcpu);
31223129
if (apic->apicv_active) {
31233130
kvm_x86_call(apicv_post_state_restore)(vcpu);
3124-
kvm_x86_call(hwapic_irr_update)(vcpu,
3125-
apic_find_highest_irr(apic));
3126-
kvm_x86_call(hwapic_isr_update)(apic_find_highest_isr(apic));
3131+
kvm_x86_call(hwapic_isr_update)(vcpu, apic_find_highest_isr(apic));
31273132
}
31283133
kvm_make_request(KVM_REQ_EVENT, vcpu);
31293134
if (ioapic_in_kernel(vcpu->kvm))

arch/x86/kvm/lapic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ void kvm_apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high);
118118
int kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value, bool host_initiated);
119119
int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s);
120120
int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s);
121+
void kvm_apic_update_hwapic_isr(struct kvm_vcpu *vcpu);
121122
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
122123

123124
u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);

arch/x86/kvm/vmx/main.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
100100
.load_eoi_exitmap = vmx_load_eoi_exitmap,
101101
.apicv_pre_state_restore = vmx_apicv_pre_state_restore,
102102
.required_apicv_inhibits = VMX_REQUIRED_APICV_INHIBITS,
103-
.hwapic_irr_update = vmx_hwapic_irr_update,
104103
.hwapic_isr_update = vmx_hwapic_isr_update,
105104
.sync_pir_to_irr = vmx_sync_pir_to_irr,
106105
.deliver_interrupt = vmx_deliver_interrupt,
@@ -126,7 +125,7 @@ struct kvm_x86_ops vt_x86_ops __initdata = {
126125
.check_intercept = vmx_check_intercept,
127126
.handle_exit_irqoff = vmx_handle_exit_irqoff,
128127

129-
.cpu_dirty_log_size = PML_ENTITY_NUM,
128+
.cpu_dirty_log_size = PML_LOG_NR_ENTRIES,
130129
.update_cpu_dirty_logging = vmx_update_cpu_dirty_logging,
131130

132131
.nested_ops = &vmx_nested_ops,

arch/x86/kvm/vmx/nested.c

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3442,7 +3442,7 @@ static int nested_vmx_write_pml_buffer(struct kvm_vcpu *vcpu, gpa_t gpa)
34423442
if (!nested_cpu_has_pml(vmcs12))
34433443
return 0;
34443444

3445-
if (vmcs12->guest_pml_index >= PML_ENTITY_NUM) {
3445+
if (vmcs12->guest_pml_index >= PML_LOG_NR_ENTRIES) {
34463446
vmx->nested.pml_full = true;
34473447
return 1;
34483448
}
@@ -3481,14 +3481,6 @@ static int nested_vmx_check_permission(struct kvm_vcpu *vcpu)
34813481
return 1;
34823482
}
34833483

3484-
static u8 vmx_has_apicv_interrupt(struct kvm_vcpu *vcpu)
3485-
{
3486-
u8 rvi = vmx_get_rvi();
3487-
u8 vppr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_PROCPRI);
3488-
3489-
return ((rvi & 0xf0) > (vppr & 0xf0));
3490-
}
3491-
34923484
static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
34933485
struct vmcs12 *vmcs12);
34943486

@@ -3508,7 +3500,6 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
35083500
struct vcpu_vmx *vmx = to_vmx(vcpu);
35093501
struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
35103502
enum vm_entry_failure_code entry_failure_code;
3511-
bool evaluate_pending_interrupts;
35123503
union vmx_exit_reason exit_reason = {
35133504
.basic = EXIT_REASON_INVALID_STATE,
35143505
.failed_vmentry = 1,
@@ -3527,13 +3518,6 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
35273518

35283519
kvm_service_local_tlb_flush_requests(vcpu);
35293520

3530-
evaluate_pending_interrupts = exec_controls_get(vmx) &
3531-
(CPU_BASED_INTR_WINDOW_EXITING | CPU_BASED_NMI_WINDOW_EXITING);
3532-
if (likely(!evaluate_pending_interrupts) && kvm_vcpu_apicv_active(vcpu))
3533-
evaluate_pending_interrupts |= vmx_has_apicv_interrupt(vcpu);
3534-
if (!evaluate_pending_interrupts)
3535-
evaluate_pending_interrupts |= kvm_apic_has_pending_init_or_sipi(vcpu);
3536-
35373521
if (!vmx->nested.nested_run_pending ||
35383522
!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
35393523
vmx->nested.pre_vmenter_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
@@ -3616,9 +3600,13 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
36163600
* Re-evaluate pending events if L1 had a pending IRQ/NMI/INIT/SIPI
36173601
* when it executed VMLAUNCH/VMRESUME, as entering non-root mode can
36183602
* effectively unblock various events, e.g. INIT/SIPI cause VM-Exit
3619-
* unconditionally.
3603+
* unconditionally. Take care to pull data from vmcs01 as appropriate,
3604+
* e.g. when checking for interrupt windows, as vmcs02 is now loaded.
36203605
*/
3621-
if (unlikely(evaluate_pending_interrupts))
3606+
if ((__exec_controls_get(&vmx->vmcs01) & (CPU_BASED_INTR_WINDOW_EXITING |
3607+
CPU_BASED_NMI_WINDOW_EXITING)) ||
3608+
kvm_apic_has_pending_init_or_sipi(vcpu) ||
3609+
kvm_apic_has_interrupt(vcpu))
36223610
kvm_make_request(KVM_REQ_EVENT, vcpu);
36233611

36243612
/*
@@ -3751,14 +3739,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
37513739
if (unlikely(status != NVMX_VMENTRY_SUCCESS))
37523740
goto vmentry_failed;
37533741

3754-
/* Emulate processing of posted interrupts on VM-Enter. */
3755-
if (nested_cpu_has_posted_intr(vmcs12) &&
3756-
kvm_apic_has_interrupt(vcpu) == vmx->nested.posted_intr_nv) {
3757-
vmx->nested.pi_pending = true;
3758-
kvm_make_request(KVM_REQ_EVENT, vcpu);
3759-
kvm_apic_clear_irr(vcpu, vmx->nested.posted_intr_nv);
3760-
}
3761-
37623742
/* Hide L1D cache contents from the nested guest. */
37633743
vmx->vcpu.arch.l1tf_flush_l1d = true;
37643744

@@ -4220,13 +4200,25 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu)
42204200
*/
42214201
bool block_nested_exceptions = vmx->nested.nested_run_pending;
42224202
/*
4223-
* New events (not exceptions) are only recognized at instruction
4203+
* Events that don't require injection, i.e. that are virtualized by
4204+
* hardware, aren't blocked by a pending VM-Enter as KVM doesn't need
4205+
* to regain control in order to deliver the event, and hardware will
4206+
* handle event ordering, e.g. with respect to injected exceptions.
4207+
*
4208+
* But, new events (not exceptions) are only recognized at instruction
42244209
* boundaries. If an event needs reinjection, then KVM is handling a
4225-
* VM-Exit that occurred _during_ instruction execution; new events are
4226-
* blocked until the instruction completes.
4210+
* VM-Exit that occurred _during_ instruction execution; new events,
4211+
* irrespective of whether or not they're injected, are blocked until
4212+
* the instruction completes.
4213+
*/
4214+
bool block_non_injected_events = kvm_event_needs_reinjection(vcpu);
4215+
/*
4216+
* Inject events are blocked by nested VM-Enter, as KVM is responsible
4217+
* for managing priority between concurrent events, i.e. KVM needs to
4218+
* wait until after VM-Enter completes to deliver injected events.
42274219
*/
42284220
bool block_nested_events = block_nested_exceptions ||
4229-
kvm_event_needs_reinjection(vcpu);
4221+
block_non_injected_events;
42304222

42314223
if (lapic_in_kernel(vcpu) &&
42324224
test_bit(KVM_APIC_INIT, &apic->pending_events)) {
@@ -4338,18 +4330,26 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu)
43384330
if (kvm_cpu_has_interrupt(vcpu) && !vmx_interrupt_blocked(vcpu)) {
43394331
int irq;
43404332

4341-
if (block_nested_events)
4342-
return -EBUSY;
4343-
if (!nested_exit_on_intr(vcpu))
4333+
if (!nested_exit_on_intr(vcpu)) {
4334+
if (block_nested_events)
4335+
return -EBUSY;
4336+
43444337
goto no_vmexit;
4338+
}
43454339

43464340
if (!nested_exit_intr_ack_set(vcpu)) {
4341+
if (block_nested_events)
4342+
return -EBUSY;
4343+
43474344
nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT, 0, 0);
43484345
return 0;
43494346
}
43504347

43514348
irq = kvm_cpu_get_extint(vcpu);
43524349
if (irq != -1) {
4350+
if (block_nested_events)
4351+
return -EBUSY;
4352+
43534353
nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT,
43544354
INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | irq, 0);
43554355
return 0;
@@ -4368,11 +4368,22 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu)
43684368
* and enabling posted interrupts requires ACK-on-exit.
43694369
*/
43704370
if (irq == vmx->nested.posted_intr_nv) {
4371+
/*
4372+
* Nested posted interrupts are delivered via RVI, i.e.
4373+
* aren't injected by KVM, and so can be queued even if
4374+
* manual event injection is disallowed.
4375+
*/
4376+
if (block_non_injected_events)
4377+
return -EBUSY;
4378+
43714379
vmx->nested.pi_pending = true;
43724380
kvm_apic_clear_irr(vcpu, irq);
43734381
goto no_vmexit;
43744382
}
43754383

4384+
if (block_nested_events)
4385+
return -EBUSY;
4386+
43764387
nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT,
43774388
INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | irq, 0);
43784389

@@ -5050,6 +5061,11 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
50505061
kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu);
50515062
}
50525063

5064+
if (vmx->nested.update_vmcs01_hwapic_isr) {
5065+
vmx->nested.update_vmcs01_hwapic_isr = false;
5066+
kvm_apic_update_hwapic_isr(vcpu);
5067+
}
5068+
50535069
if ((vm_exit_reason != -1) &&
50545070
(enable_shadow_vmcs || nested_vmx_is_evmptr12_valid(vmx)))
50555071
vmx->nested.need_vmcs12_to_shadow_sync = true;

0 commit comments

Comments
 (0)