[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [ PATCH 2/2] xen: enable Virtual-interrupt delivery


  • To: "xen-devel@xxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxx>
  • From: "Li, Jiongxi" <jiongxi.li@xxxxxxxxx>
  • Date: Fri, 31 Aug 2012 09:30:13 +0000
  • Accept-language: en-US
  • Delivery-date: Fri, 31 Aug 2012 09:30:40 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xen.org>
  • Thread-index: Ac2HWp7G2HqBx++QQP2kPrY5SPXyLg==
  • Thread-topic: [ PATCH 2/2] xen: enable Virtual-interrupt delivery

Virtual interrupt delivery avoids Xen to inject vAPIC interrupts manually, 
which is fully taken care of by the hardware. This needs some special awareness 
into existing interrupr injection path:
For pending interrupt from vLAPIC, instead of direct injection, we may need 
update architecture specific indicators before resuming to guest.
Before returning to guest, RVI should be updated if any pending IRRs
EOI exit bitmap controls whether an EOI write should cause VM-Exit. If set, a 
trap-like induced EOI VM-Exit is triggered. The approach here is to manipulate 
EOI exit bitmap based on value of TMR. Level triggered irq requires a hook in 
vLAPIC EOI write, so that vIOAPIC EOI is triggered and emulated

Signed-off-by: Yang Zhang <yang.z.zhang@xxxxxxxxx>
Signed-off-by: Jiongxi Li <jiongxi.li@xxxxxxxxx>

diff -r cb821c24ca74 xen/arch/x86/hvm/irq.c
--- a/xen/arch/x86/hvm/irq.c  Fri Aug 31 09:30:38 2012 +0800
+++ b/xen/arch/x86/hvm/irq.c         Fri Aug 31 09:49:39 2012 +0800
@@ -452,7 +452,11 @@ struct hvm_intack hvm_vcpu_ack_pending_i

 int hvm_local_events_need_delivery(struct vcpu *v)
{
-    struct hvm_intack intack = hvm_vcpu_has_pending_irq(v);
+    struct hvm_intack intack;
+
+    pt_update_irq(v);
+
+    intack = hvm_vcpu_has_pending_irq(v);

     if ( likely(intack.source == hvm_intsrc_none) )
         return 0;
diff -r cb821c24ca74 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c      Fri Aug 31 09:30:38 2012 +0800
+++ b/xen/arch/x86/hvm/vlapic.c   Fri Aug 31 09:49:39 2012 +0800
@@ -143,7 +143,16 @@ static int vlapic_find_highest_irr(struc
int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig)
{
     if ( trig )
+    {
         vlapic_set_vector(vec, &vlapic->regs->data[APIC_TMR]);
+        if ( cpu_has_vmx_virtual_intr_delivery )
+            vmx_set_eoi_exit_bitmap(vlapic_vcpu(vlapic), vec);
+    }
+    else
+    {
+        if ( cpu_has_vmx_virtual_intr_delivery )
+            vmx_clear_eoi_exit_bitmap(vlapic_vcpu(vlapic), vec);
+    }

     /* We may need to wake up target vcpu, besides set pending bit here */
     return !vlapic_test_and_set_irr(vec, vlapic);
@@ -410,6 +419,22 @@ void vlapic_EOI_set(struct vlapic *vlapi
     hvm_dpci_msi_eoi(current->domain, vector);
}

+/*
+ * When "Virtual Interrupt Delivery" is enabled, this function is used
+ * to handle EOI-induced VM exit
+ */
+void vlapic_handle_EOI_induced_exit(struct vlapic *vlapic, int vector)
+{
+    ASSERT(cpu_has_vmx_virtual_intr_delivery);
+
+    if ( vlapic_test_and_clear_vector(vector, &vlapic->regs->data[APIC_TMR]) )
+    {
+        vioapic_update_EOI(vlapic_domain(vlapic), vector);
+    }
+
+    hvm_dpci_msi_eoi(current->domain, vector);
+}
+
int vlapic_ipi(
     struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high)
{
@@ -1014,6 +1039,9 @@ int vlapic_has_pending_irq(struct vcpu *
     if ( irr == -1 )
         return -1;

+    if ( cpu_has_vmx_virtual_intr_delivery )
+        return irr;
+
     isr = vlapic_find_highest_isr(vlapic);
     isr = (isr != -1) ? isr : 0;
     if ( (isr & 0xf0) >= (irr & 0xf0) )
@@ -1026,6 +1054,9 @@ int vlapic_ack_pending_irq(struct vcpu *
{
     struct vlapic *vlapic = vcpu_vlapic(v);

+    if ( cpu_has_vmx_virtual_intr_delivery )
+        return 1;
+
    vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]);
     vlapic_clear_irr(vector, vlapic);

diff -r cb821c24ca74 xen/arch/x86/hvm/vmx/intr.c
--- a/xen/arch/x86/hvm/vmx/intr.c Fri Aug 31 09:30:38 2012 +0800
+++ b/xen/arch/x86/hvm/vmx/intr.c       Fri Aug 31 09:49:39 2012 +0800
@@ -227,19 +227,43 @@ void vmx_intr_assist(void)
             goto out;

         intblk = hvm_interrupt_blocked(v, intack);
-        if ( intblk == hvm_intblk_tpr )
+        if ( cpu_has_vmx_virtual_intr_delivery )
         {
-            ASSERT(vlapic_enabled(vcpu_vlapic(v)));
-            ASSERT(intack.source == hvm_intsrc_lapic);
-            tpr_threshold = intack.vector >> 4;
-            goto out;
+            /* Set "Interrupt-window exiting" for ExtINT */
+            if ( (intblk != hvm_intblk_none) &&
+                 ( (intack.source == hvm_intsrc_pic) ||
+                 ( intack.source == hvm_intsrc_vector) ) )
+            {
+                enable_intr_window(v, intack);
+                goto out;
+            }
+
+            if ( __vmread(VM_ENTRY_INTR_INFO) & INTR_INFO_VALID_MASK )
+            {
+                if ( (intack.source == hvm_intsrc_pic) ||
+                     (intack.source == hvm_intsrc_nmi) ||
+                     (intack.source == hvm_intsrc_mce) )
+                    enable_intr_window(v, intack);
+
+                goto out;
+            }
         }
+        else
+        {
+            if ( intblk == hvm_intblk_tpr )
+            {
+                ASSERT(vlapic_enabled(vcpu_vlapic(v)));
+                ASSERT(intack.source == hvm_intsrc_lapic);
+                tpr_threshold = intack.vector >> 4;
+                goto out;
+            }

-        if ( (intblk != hvm_intblk_none) ||
-             (__vmread(VM_ENTRY_INTR_INFO) & INTR_INFO_VALID_MASK) )
-        {
-            enable_intr_window(v, intack);
-            goto out;
+            if ( (intblk != hvm_intblk_none) ||
+                 (__vmread(VM_ENTRY_INTR_INFO) & INTR_INFO_VALID_MASK) )
+            {
+                enable_intr_window(v, intack);
+                goto out;
+            }
         }

         intack = hvm_vcpu_ack_pending_irq(v, intack);
@@ -253,6 +277,29 @@ void vmx_intr_assist(void)
     {
         hvm_inject_hw_exception(TRAP_machine_check, HVM_DELIVER_NO_ERROR_CODE);
     }
+    else if ( cpu_has_vmx_virtual_intr_delivery &&
+              intack.source != hvm_intsrc_pic &&
+              intack.source != hvm_intsrc_vector )
+    {
+        /* we need update the RVI field */
+        unsigned long status = __vmread(GUEST_INTR_STATUS);
+        status &= ~(unsigned long)0x0FF;
+        status |= (unsigned long)0x0FF & 
+                    intack.vector;
+        __vmwrite(GUEST_INTR_STATUS, status);
+        if (v->arch.hvm_vmx.eoi_exitmap_changed) {
+#define UPDATE_EOI_EXITMAP(v, e) {                             \
+        if (test_and_clear_bit(e, &(v).eoi_exitmap_changed)) {      \
+                __vmwrite(EOI_EXIT_BITMAP##e, (v).eoi_exit_bitmap[e]);}}
+
+                UPDATE_EOI_EXITMAP(v->arch.hvm_vmx, 0);
+                UPDATE_EOI_EXITMAP(v->arch.hvm_vmx, 1);
+                UPDATE_EOI_EXITMAP(v->arch.hvm_vmx, 2);
+                UPDATE_EOI_EXITMAP(v->arch.hvm_vmx, 3);
+        }
+
+        pt_intr_post(v, intack);
+    }
     else
     {
         HVMTRACE_2D(INJ_VIRQ, intack.vector, /*fake=*/ 0);
@@ -262,11 +309,16 @@ void vmx_intr_assist(void)

     /* Is there another IRQ to queue up behind this one? */
     intack = hvm_vcpu_has_pending_irq(v);
-    if ( unlikely(intack.source != hvm_intsrc_none) )
-        enable_intr_window(v, intack);
+    if ( !cpu_has_vmx_virtual_intr_delivery ||
+         intack.source == hvm_intsrc_pic ||
+         intack.source == hvm_intsrc_vector )
+    {
+        if ( unlikely(intack.source != hvm_intsrc_none) )
+            enable_intr_window(v, intack);
+    }

  out:
-    if ( cpu_has_vmx_tpr_shadow )
+    if ( !cpu_has_vmx_virtual_intr_delivery && cpu_has_vmx_tpr_shadow )
         __vmwrite(TPR_THRESHOLD, tpr_threshold);
}

diff -r cb821c24ca74 xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c       Fri Aug 31 09:30:38 2012 +0800
+++ b/xen/arch/x86/hvm/vmx/vmcs.c    Fri Aug 31 09:49:39 2012 +0800
@@ -90,6 +90,7 @@ static void __init vmx_display_features(
     P(cpu_has_vmx_msr_bitmap, "MSR direct-access bitmap");
     P(cpu_has_vmx_unrestricted_guest, "Unrestricted Guest");
     P(cpu_has_vmx_apic_reg_virt, "APIC Register Virtualization");
+    P(cpu_has_vmx_virtual_intr_delivery, "Virtual Interrupt Delivery");
#undef P

     if ( !printed )
@@ -188,11 +189,12 @@ static int vmx_init_vmcs_config(void)
             opt |= SECONDARY_EXEC_UNRESTRICTED_GUEST;

         /*
-         * "APIC Register Virtualization"
+         * "APIC Register Virtualization" and "Virtual Interrupt Delivery"
          * can be set only when "use TPR shadow" is set
          */
         if ( _vmx_cpu_based_exec_control & CPU_BASED_TPR_SHADOW )
-            opt |= SECONDARY_EXEC_APIC_REGISTER_VIRT;
+            opt |= SECONDARY_EXEC_APIC_REGISTER_VIRT |
+                   SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY;

 
         _vmx_secondary_exec_control = adjust_vmx_controls(
@@ -787,6 +789,22 @@ static int construct_vmcs(struct vcpu *v
     __vmwrite(IO_BITMAP_A, virt_to_maddr((char *)hvm_io_bitmap + 0));
     __vmwrite(IO_BITMAP_B, virt_to_maddr((char *)hvm_io_bitmap + PAGE_SIZE));

+    if ( cpu_has_vmx_virtual_intr_delivery )
+    {
+        /* EOI-exit bitmap */
+        v->arch.hvm_vmx.eoi_exit_bitmap[0] = (uint64_t)0;
+        __vmwrite(EOI_EXIT_BITMAP0, v->arch.hvm_vmx.eoi_exit_bitmap[0]);
+        v->arch.hvm_vmx.eoi_exit_bitmap[1] = (uint64_t)0;
+        __vmwrite(EOI_EXIT_BITMAP1, v->arch.hvm_vmx.eoi_exit_bitmap[1]);
+        v->arch.hvm_vmx.eoi_exit_bitmap[2] = (uint64_t)0;
+        __vmwrite(EOI_EXIT_BITMAP2, v->arch.hvm_vmx.eoi_exit_bitmap[2]);
+        v->arch.hvm_vmx.eoi_exit_bitmap[3] = (uint64_t)0;
+        __vmwrite(EOI_EXIT_BITMAP3, v->arch.hvm_vmx.eoi_exit_bitmap[3]);
+
+        /* Initialise Guest Interrupt Status (RVI and SVI) to 0 */
+        __vmwrite(GUEST_INTR_STATUS, 0);
+    }
+
     /* Host data selectors. */
     __vmwrite(HOST_SS_SELECTOR, __HYPERVISOR_DS);
     __vmwrite(HOST_DS_SELECTOR, __HYPERVISOR_DS);
@@ -1028,6 +1046,30 @@ int vmx_add_host_load_msr(u32 msr)
     return 0;
}

+void vmx_set_eoi_exit_bitmap(struct vcpu *v, u8 vector)
+{
+    int index, offset, changed;
+
+    index = vector >> 6; 
+    offset = vector & 63;
+    changed = !test_and_set_bit(offset,
+                  (uint64_t *)&v->arch.hvm_vmx.eoi_exit_bitmap[index]);
+    if (changed)
+        set_bit(index, &v->arch.hvm_vmx.eoi_exitmap_changed);
+}
+
+void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector)
+{
+    int index, offset, changed;
+
+    index = vector >> 6; 
+    offset = vector & 63;
+    changed = test_and_clear_bit(offset,
+                  (uint64_t *)&v->arch.hvm_vmx.eoi_exit_bitmap[index]);
+    if (changed)
+        set_bit(index, &v->arch.hvm_vmx.eoi_exitmap_changed);
+}
+
int vmx_create_vmcs(struct vcpu *v)
{
     struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
diff -r cb821c24ca74 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c         Fri Aug 31 09:30:38 2012 +0800
+++ b/xen/arch/x86/hvm/vmx/vmx.c      Fri Aug 31 09:49:39 2012 +0800
@@ -2674,6 +2674,16 @@ void vmx_vmexit_handler(struct cpu_user_
             hvm_inject_hw_exception(TRAP_gp_fault, 0);
         break;

+    case EXIT_REASON_EOI_INDUCED:
+    {
+        int vector;
+        exit_qualification = __vmread(EXIT_QUALIFICATION);
+        vector = exit_qualification & 0xff;
+
+        vlapic_handle_EOI_induced_exit(vcpu_vlapic(current), vector);
+        break;
+    }
+
     case EXIT_REASON_IO_INSTRUCTION:
         exit_qualification = __vmread(EXIT_QUALIFICATION);
         if ( exit_qualification & 0x10 )
diff -r cb821c24ca74 xen/include/asm-x86/hvm/vlapic.h
--- a/xen/include/asm-x86/hvm/vlapic.h Fri Aug 31 09:30:38 2012 +0800
+++ b/xen/include/asm-x86/hvm/vlapic.h       Fri Aug 31 09:49:39 2012 +0800
@@ -100,6 +100,7 @@ int vlapic_accept_pic_intr(struct vcpu *
void vlapic_adjust_i8259_target(struct domain *d);

 void vlapic_EOI_set(struct vlapic *vlapic);
+void vlapic_handle_EOI_induced_exit(struct vlapic *vlapic, int vector);

 int vlapic_ipi(struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high);

diff -r cb821c24ca74 xen/include/asm-x86/hvm/vmx/vmcs.h
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h  Fri Aug 31 09:30:38 2012 +0800
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h        Fri Aug 31 09:49:39 2012 +0800
@@ -110,6 +110,9 @@ struct arch_vmx_struct {
     unsigned int         host_msr_count;
     struct vmx_msr_entry *host_msr_area;

+    uint32_t             eoi_exitmap_changed;
+    uint64_t             eoi_exit_bitmap[4];
+
     unsigned long        host_cr0;

     /* Is the guest in real mode? */
@@ -183,6 +186,7 @@ extern u32 vmx_vmentry_control;
#define SECONDARY_EXEC_WBINVD_EXITING           0x00000040
#define SECONDARY_EXEC_UNRESTRICTED_GUEST       0x00000080
#define SECONDARY_EXEC_APIC_REGISTER_VIRT       0x00000100
+#define SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY    0x00000200
#define SECONDARY_EXEC_PAUSE_LOOP_EXITING       0x00000400
#define SECONDARY_EXEC_ENABLE_INVPCID           0x00001000
extern u32 vmx_secondary_exec_control;
@@ -233,6 +237,8 @@ extern bool_t cpu_has_vmx_ins_outs_instr
     (vmx_secondary_exec_control & SECONDARY_EXEC_PAUSE_LOOP_EXITING)
#define cpu_has_vmx_apic_reg_virt \
     (vmx_secondary_exec_control & SECONDARY_EXEC_APIC_REGISTER_VIRT)
+#define cpu_has_vmx_virtual_intr_delivery \
+    (vmx_secondary_exec_control & SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)

 /* GUEST_INTERRUPTIBILITY_INFO flags. */
#define VMX_INTR_SHADOW_STI             0x00000001
@@ -251,6 +257,7 @@ enum vmcs_field {
     GUEST_GS_SELECTOR               = 0x0000080a,
     GUEST_LDTR_SELECTOR             = 0x0000080c,
     GUEST_TR_SELECTOR               = 0x0000080e,
+    GUEST_INTR_STATUS               = 0x00000810,
     HOST_ES_SELECTOR                = 0x00000c00,
     HOST_CS_SELECTOR                = 0x00000c02,
     HOST_SS_SELECTOR                = 0x00000c04,
@@ -278,6 +285,14 @@ enum vmcs_field {
     APIC_ACCESS_ADDR_HIGH           = 0x00002015,
     EPT_POINTER                     = 0x0000201a,
     EPT_POINTER_HIGH                = 0x0000201b,
+    EOI_EXIT_BITMAP0                = 0x0000201c,
+    EOI_EXIT_BITMAP0_HIGH           = 0x0000201d,
+    EOI_EXIT_BITMAP1                = 0x0000201e,
+    EOI_EXIT_BITMAP1_HIGH           = 0x0000201f,
+    EOI_EXIT_BITMAP2                = 0x00002020,
+    EOI_EXIT_BITMAP2_HIGH           = 0x00002021,
+    EOI_EXIT_BITMAP3                = 0x00002022,
+    EOI_EXIT_BITMAP3_HIGH           = 0x00002023,
    GUEST_PHYSICAL_ADDRESS          = 0x00002400,
     GUEST_PHYSICAL_ADDRESS_HIGH     = 0x00002401,
     VMCS_LINK_POINTER               = 0x00002800,
@@ -398,6 +413,8 @@ int vmx_write_guest_msr(u32 msr, u64 val
int vmx_add_guest_msr(u32 msr);
int vmx_add_host_load_msr(u32 msr);
void vmx_vmcs_switch(struct vmcs_struct *from, struct vmcs_struct *to);
+void vmx_set_eoi_exit_bitmap(struct vcpu *v, u8 vector);
+void vmx_clear_eoi_exit_bitmap(struct vcpu *v, u8 vector);

 #endif /* ASM_X86_HVM_VMX_VMCS_H__ */

diff -r cb821c24ca74 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h    Fri Aug 31 09:30:38 2012 +0800
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Fri Aug 31 09:49:39 2012 +0800
@@ -119,6 +119,7 @@ void vmx_update_cpu_exec_control(struct 
 #define EXIT_REASON_MCE_DURING_VMENTRY  41
#define EXIT_REASON_TPR_BELOW_THRESHOLD 43
#define EXIT_REASON_APIC_ACCESS         44
+#define EXIT_REASON_EOI_INDUCED         45
#define EXIT_REASON_ACCESS_GDTR_OR_IDTR 46
#define EXIT_REASON_ACCESS_LDTR_OR_TR   47
#define EXIT_REASON_EPT_VIOLATION       48

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.