lkml.org 
[lkml]   [2020]   [Apr]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 125/232] KVM: nVMX: Properly handle userspace interrupt window request
    Date
    From: Sean Christopherson <sean.j.christopherson@intel.com>

    commit a1c77abb8d93381e25a8d2df3a917388244ba776 upstream.

    Return true for vmx_interrupt_allowed() if the vCPU is in L2 and L1 has
    external interrupt exiting enabled. IRQs are never blocked in hardware
    if the CPU is in the guest (L2 from L1's perspective) when IRQs trigger
    VM-Exit.

    The new check percolates up to kvm_vcpu_ready_for_interrupt_injection()
    and thus vcpu_run(), and so KVM will exit to userspace if userspace has
    requested an interrupt window (to inject an IRQ into L1).

    Remove the @external_intr param from vmx_check_nested_events(), which is
    actually an indicator that userspace wants an interrupt window, e.g.
    it's named @req_int_win further up the stack. Injecting a VM-Exit into
    L1 to try and bounce out to L0 userspace is all kinds of broken and is
    no longer necessary.

    Remove the hack in nested_vmx_vmexit() that attempted to workaround the
    breakage in vmx_check_nested_events() by only filling interrupt info if
    there's an actual interrupt pending. The hack actually made things
    worse because it caused KVM to _never_ fill interrupt info when the
    LAPIC resides in userspace (kvm_cpu_has_interrupt() queries
    interrupt.injected, which is always cleared by prepare_vmcs12() before
    reaching the hack in nested_vmx_vmexit()).

    Fixes: 6550c4df7e50 ("KVM: nVMX: Fix interrupt window request with "Acknowledge interrupt on exit"")
    Cc: stable@vger.kernel.org
    Cc: Liran Alon <liran.alon@oracle.com>
    Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    arch/x86/include/asm/kvm_host.h | 2 +-
    arch/x86/kvm/vmx/nested.c | 18 ++++--------------
    arch/x86/kvm/vmx/vmx.c | 9 +++++++--
    arch/x86/kvm/x86.c | 10 +++++-----
    4 files changed, 17 insertions(+), 22 deletions(-)

    --- a/arch/x86/include/asm/kvm_host.h
    +++ b/arch/x86/include/asm/kvm_host.h
    @@ -1130,7 +1130,7 @@ struct kvm_x86_ops {
    bool (*pt_supported)(void);
    bool (*pku_supported)(void);

    - int (*check_nested_events)(struct kvm_vcpu *vcpu, bool external_intr);
    + int (*check_nested_events)(struct kvm_vcpu *vcpu);
    void (*request_immediate_exit)(struct kvm_vcpu *vcpu);

    void (*sched_in)(struct kvm_vcpu *kvm, int cpu);
    --- a/arch/x86/kvm/vmx/nested.c
    +++ b/arch/x86/kvm/vmx/nested.c
    @@ -3460,7 +3460,7 @@ static void nested_vmx_inject_exception_
    nested_vmx_vmexit(vcpu, EXIT_REASON_EXCEPTION_NMI, intr_info, exit_qual);
    }

    -static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
    +static int vmx_check_nested_events(struct kvm_vcpu *vcpu)
    {
    struct vcpu_vmx *vmx = to_vmx(vcpu);
    unsigned long exit_qual;
    @@ -3507,8 +3507,7 @@ static int vmx_check_nested_events(struc
    return 0;
    }

    - if ((kvm_cpu_has_interrupt(vcpu) || external_intr) &&
    - nested_exit_on_intr(vcpu)) {
    + if (kvm_cpu_has_interrupt(vcpu) && nested_exit_on_intr(vcpu)) {
    if (block_nested_events)
    return -EBUSY;
    nested_vmx_vmexit(vcpu, EXIT_REASON_EXTERNAL_INTERRUPT, 0, 0);
    @@ -4158,17 +4157,8 @@ void nested_vmx_vmexit(struct kvm_vcpu *
    vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;

    if (likely(!vmx->fail)) {
    - /*
    - * TODO: SDM says that with acknowledge interrupt on
    - * exit, bit 31 of the VM-exit interrupt information
    - * (valid interrupt) is always set to 1 on
    - * EXIT_REASON_EXTERNAL_INTERRUPT, so we shouldn't
    - * need kvm_cpu_has_interrupt(). See the commit
    - * message for details.
    - */
    - if (nested_exit_intr_ack_set(vcpu) &&
    - exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT &&
    - kvm_cpu_has_interrupt(vcpu)) {
    + if (exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT &&
    + nested_exit_intr_ack_set(vcpu)) {
    int irq = kvm_cpu_get_interrupt(vcpu);
    WARN_ON(irq < 0);
    vmcs12->vm_exit_intr_info = irq |
    --- a/arch/x86/kvm/vmx/vmx.c
    +++ b/arch/x86/kvm/vmx/vmx.c
    @@ -4505,8 +4505,13 @@ static int vmx_nmi_allowed(struct kvm_vc

    static int vmx_interrupt_allowed(struct kvm_vcpu *vcpu)
    {
    - return (!to_vmx(vcpu)->nested.nested_run_pending &&
    - vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
    + if (to_vmx(vcpu)->nested.nested_run_pending)
    + return false;
    +
    + if (is_guest_mode(vcpu) && nested_exit_on_intr(vcpu))
    + return true;
    +
    + return (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) &&
    !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
    (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS));
    }
    --- a/arch/x86/kvm/x86.c
    +++ b/arch/x86/kvm/x86.c
    @@ -7555,7 +7555,7 @@ static void update_cr8_intercept(struct
    kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr);
    }

    -static int inject_pending_event(struct kvm_vcpu *vcpu, bool req_int_win)
    +static int inject_pending_event(struct kvm_vcpu *vcpu)
    {
    int r;

    @@ -7591,7 +7591,7 @@ static int inject_pending_event(struct k
    * from L2 to L1.
    */
    if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) {
    - r = kvm_x86_ops->check_nested_events(vcpu, req_int_win);
    + r = kvm_x86_ops->check_nested_events(vcpu);
    if (r != 0)
    return r;
    }
    @@ -7653,7 +7653,7 @@ static int inject_pending_event(struct k
    * KVM_REQ_EVENT only on certain events and not unconditionally?
    */
    if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events) {
    - r = kvm_x86_ops->check_nested_events(vcpu, req_int_win);
    + r = kvm_x86_ops->check_nested_events(vcpu);
    if (r != 0)
    return r;
    }
    @@ -8130,7 +8130,7 @@ static int vcpu_enter_guest(struct kvm_v
    goto out;
    }

    - if (inject_pending_event(vcpu, req_int_win) != 0)
    + if (inject_pending_event(vcpu) != 0)
    req_immediate_exit = true;
    else {
    /* Enable SMI/NMI/IRQ window open exits if needed.
    @@ -8360,7 +8360,7 @@ static inline int vcpu_block(struct kvm
    static inline bool kvm_vcpu_running(struct kvm_vcpu *vcpu)
    {
    if (is_guest_mode(vcpu) && kvm_x86_ops->check_nested_events)
    - kvm_x86_ops->check_nested_events(vcpu, false);
    + kvm_x86_ops->check_nested_events(vcpu);

    return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE &&
    !vcpu->arch.apf.halted);

    \
     
     \ /
      Last update: 2020-04-16 17:21    [W:3.199 / U:0.028 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site