Skip to content
  • Nadav Har'El's avatar
    KVM: nVMX: Fix warning-causing idt-vectoring-info behavior · 51cfe38e
    Nadav Har'El authored
    
    
    When L0 wishes to inject an interrupt while L2 is running, it emulates an exit
    to L1 with EXIT_REASON_EXTERNAL_INTERRUPT. This was explained in the original
    nVMX patch 23, titled "Correct handling of interrupt injection".
    
    Unfortunately, it is possible (though rare) that at this point there is valid
    idt_vectoring_info in vmcs02. For example, L1 injected some interrupt to L2,
    and when L2 tried to run this interrupt's handler, it got a page fault - so
    it returns the original interrupt vector in idt_vectoring_info. The problem
    is that if this is the case, we cannot exit to L1 with EXTERNAL_INTERRUPT
    like we wished to, because the VMX spec guarantees that idt_vectoring_info
    and exit_reason_external_interrupt can never happen together. This is not
    just specified in the spec - a KVM L1 actually prints a kernel warning
    "unexpected, valid vectoring info" if we violate this guarantee, and some
    users noticed these warnings in L1's logs.
    
    In order to better emulate a processor, which would never return the external
    interrupt and the idt-vectoring-info together, we need to separate the two
    injection steps: First, complete L1's injection into L2 (i.e., enter L2,
    injecting to it the idt-vectoring-info); Second, after entry into L2 succeeds
    and it exits back to L0, exit to L1 with the EXIT_REASON_EXTERNAL_INTERRUPT.
    Most of this is already in the code - the only change we need is to remain
    in L2 (and not exit to L1) in this case.
    
    Note that the previous patch ensures (by using KVM_REQ_IMMEDIATE_EXIT) that
    although we do enter L2 first, it will exit immediately after processing its
    injection, allowing us to promptly inject to L1.
    
    Note how we test vmcs12->idt_vectoring_info_field; This isn't really the
    vmcs12 value (we haven't exited to L1 yet, so vmcs12 hasn't been updated),
    but rather the place we save, at the end of vmx_vcpu_run, the vmcs02 value
    of this field. This was explained in patch 25 ("Correct handling of idt
    vectoring info") of the original nVMX patch series.
    
    Thanks to Dave Allan and to Federico Simoncelli for reporting this bug,
    to Abel Gordon for helping me figure out the solution, and to Avi Kivity
    for helping to improve it.
    
    Signed-off-by: default avatarNadav Har'El <nyh@il.ibm.com>
    Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
    51cfe38e