This patch adds correct handling of IDT_VECTORING_INFO_FIELD for the nested
case.

When a guest exits while handling an interrupt or exception, we get this
information in IDT_VECTORING_INFO_FIELD in the VMCS. When L2 exits to L1,
there's nothing we need to do, because L1 will see this field in vmcs12, and
handle it itself. However, when L2 exits and L0 handles the exit itself and
plans to return to L2, L0 must inject this event to L2.

In the normal non-nested case, the idt_vectoring_info case is treated after
the exit. However, in the nested case a decision of whether to return to L2
or L1 also happens during the injection phase (see the previous patches), so
in the nested case we have to treat the idt_vectoring_info right after the
injection, i.e., in the beginning of vmx_vcpu_run, which is the first time
we know for sure if we're staying in L2 (i.e., nested_mode is true).

Signed-off-by: Nadav Har'El <n...@il.ibm.com>
---
--- .before/arch/x86/kvm/vmx.c  2010-06-13 15:01:30.000000000 +0300
+++ .after/arch/x86/kvm/vmx.c   2010-06-13 15:01:30.000000000 +0300
@@ -320,6 +320,10 @@ struct nested_vmx {
        struct vmcs *l1_vmcs;
        /* L2 must run next, and mustn't decide to exit to L1. */
        bool nested_run_pending;
+       /* true if last exit was of L2, and had a valid idt_vectoring_info */
+       bool valid_idt_vectoring_info;
+       /* These are saved if valid_idt_vectoring_info */
+       u32 vm_exit_instruction_len, idt_vectoring_error_code;
 };
 
 enum vmcs_field_type {
@@ -5460,6 +5464,22 @@ static void fixup_rmode_irq(struct vcpu_
                | vmx->rmode.irq.vector;
 }
 
+static void nested_handle_valid_idt_vectoring_info(struct vcpu_vmx *vmx)
+{
+       int irq  = vmx->idt_vectoring_info & VECTORING_INFO_VECTOR_MASK;
+       int type = vmx->idt_vectoring_info & VECTORING_INFO_TYPE_MASK;
+       int errCodeValid = vmx->idt_vectoring_info &
+               VECTORING_INFO_DELIVER_CODE_MASK;
+       vmcs_write32(VM_ENTRY_INTR_INFO_FIELD,
+               irq | type | INTR_INFO_VALID_MASK | errCodeValid);
+
+       vmcs_write32(VM_ENTRY_INSTRUCTION_LEN,
+               vmx->nested.vm_exit_instruction_len);
+       if (errCodeValid)
+               vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE,
+                       vmx->nested.idt_vectoring_error_code);
+}
+
 static inline void sync_cached_regs_to_vmcs(struct kvm_vcpu *vcpu)
 {
        if (test_bit(VCPU_REGS_RSP, (unsigned long *)&vcpu->arch.regs_dirty))
@@ -5481,6 +5501,9 @@ static void vmx_vcpu_run(struct kvm_vcpu
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
 
+       if (vmx->nested.nested_mode && vmx->nested.valid_idt_vectoring_info)
+               nested_handle_valid_idt_vectoring_info(vmx);
+
        /* Record the guest's net vcpu time for enforced NMI injections. */
        if (unlikely(!cpu_has_virtual_nmis() && vmx->soft_vnmi_blocked))
                vmx->entry_time = ktime_get();
@@ -5600,6 +5623,16 @@ static void vmx_vcpu_run(struct kvm_vcpu
                                  | (1 << VCPU_EXREG_PDPTR));
 
        vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
+
+       vmx->nested.valid_idt_vectoring_info = vmx->nested.nested_mode &&
+               (vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK);
+       if (vmx->nested.valid_idt_vectoring_info) {
+               vmx->nested.vm_exit_instruction_len =
+                       vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+               vmx->nested.idt_vectoring_error_code =
+                       vmcs_read32(IDT_VECTORING_ERROR_CODE);
+       }
+
        if (vmx->rmode.irq.pending)
                fixup_rmode_irq(vmx);
 
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to