Author: neel
Date: Sat Jan 11 03:14:05 2014
New Revision: 260531
URL: http://svnweb.freebsd.org/changeset/base/260531

Log:
  Enable the "Acknowledge Interrupt on VM exit" VM-exit control.
  
  This control is needed to enable "Posted Interrupts" and is present in all
  the Intel VT-x implementations supported by bhyve so enable it as the default.
  
  With this VM-exit control enabled the processor will acknowledge the APIC and
  store the vector number in the "VM-Exit Interruption Information" field. We
  now call the interrupt handler "by hand" through the IDT entry associated
  with the vector.

Modified:
  head/sys/amd64/vmm/intel/vmcs.c
  head/sys/amd64/vmm/intel/vmcs.h
  head/sys/amd64/vmm/intel/vmx.c
  head/sys/amd64/vmm/intel/vmx.h
  head/sys/amd64/vmm/intel/vmx_genassym.c
  head/sys/amd64/vmm/intel/vmx_support.S

Modified: head/sys/amd64/vmm/intel/vmcs.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmcs.c     Sat Jan 11 01:50:45 2014        
(r260530)
+++ head/sys/amd64/vmm/intel/vmcs.c     Sat Jan 11 03:14:05 2014        
(r260531)
@@ -473,7 +473,7 @@ DB_SHOW_COMMAND(vmcs, db_show_vmcs)
        switch (exit & 0x8000ffff) {
        case EXIT_REASON_EXCEPTION:
        case EXIT_REASON_EXT_INTR:
-               val = vmcs_read(VMCS_EXIT_INTERRUPTION_INFO);
+               val = vmcs_read(VMCS_EXIT_INTR_INFO);
                db_printf("Interrupt Type: ");
                switch (val >> 8 & 0x7) {
                case 0:
@@ -495,7 +495,7 @@ DB_SHOW_COMMAND(vmcs, db_show_vmcs)
                db_printf("  Vector: %lu", val & 0xff);
                if (val & 0x800)
                        db_printf("  Error Code: %lx",
-                           vmcs_read(VMCS_EXIT_INTERRUPTION_ERROR));
+                           vmcs_read(VMCS_EXIT_INTR_ERRCODE));
                db_printf("\n");
                break;
        case EXIT_REASON_EPT_FAULT:

Modified: head/sys/amd64/vmm/intel/vmcs.h
==============================================================================
--- head/sys/amd64/vmm/intel/vmcs.h     Sat Jan 11 01:50:45 2014        
(r260530)
+++ head/sys/amd64/vmm/intel/vmcs.h     Sat Jan 11 03:14:05 2014        
(r260531)
@@ -177,8 +177,8 @@ vmcs_write(uint32_t encoding, uint64_t v
 /* 32-bit read-only data fields */
 #define        VMCS_INSTRUCTION_ERROR          0x00004400
 #define        VMCS_EXIT_REASON                0x00004402
-#define        VMCS_EXIT_INTERRUPTION_INFO     0x00004404
-#define        VMCS_EXIT_INTERRUPTION_ERROR    0x00004406
+#define        VMCS_EXIT_INTR_INFO             0x00004404
+#define        VMCS_EXIT_INTR_ERRCODE          0x00004406
 #define        VMCS_IDT_VECTORING_INFO         0x00004408
 #define        VMCS_IDT_VECTORING_ERROR        0x0000440A
 #define        VMCS_EXIT_INSTRUCTION_LENGTH    0x0000440C
@@ -331,9 +331,10 @@ vmcs_write(uint32_t encoding, uint64_t v
 /*
  * VMCS interrupt information fields
  */
-#define        VMCS_INTERRUPTION_INFO_VALID    (1U << 31)
-#define        VMCS_INTERRUPTION_INFO_HW_INTR  (0 << 8)
-#define        VMCS_INTERRUPTION_INFO_NMI      (2 << 8)
+#define        VMCS_INTR_INFO_VALID            (1U << 31)
+#define        VMCS_INTR_INFO_TYPE(info)       (((info) >> 8) & 0x7)
+#define        VMCS_INTR_INFO_HW_INTR          (0 << 8)
+#define        VMCS_INTR_INFO_NMI              (2 << 8)
 
 /*
  * VMCS IDT-Vectoring information fields

Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c      Sat Jan 11 01:50:45 2014        
(r260530)
+++ head/sys/amd64/vmm/intel/vmx.c      Sat Jan 11 03:14:05 2014        
(r260531)
@@ -93,6 +93,7 @@ __FBSDID("$FreeBSD$");
 
 #define        VM_EXIT_CTLS_ONE_SETTING                                        
\
        (VM_EXIT_CTLS_ONE_SETTING_NO_PAT        |                       \
+       VM_EXIT_ACKNOWLEDGE_INTERRUPT           |                       \
        VM_EXIT_SAVE_PAT                        |                       \
        VM_EXIT_LOAD_PAT)
 #define        VM_EXIT_CTLS_ZERO_SETTING       VM_EXIT_SAVE_DEBUG_CONTROLS
@@ -680,6 +681,31 @@ vmx_init(int ipinum)
        return (0);
 }
 
+static void
+vmx_trigger_hostintr(int vector)
+{
+       uintptr_t func;
+       struct gate_descriptor *gd;
+
+       gd = &idt[vector];
+
+       KASSERT(vector >= 32 && vector <= 255, ("vmx_trigger_hostintr: "
+           "invalid vector %d", vector));
+       KASSERT(gd->gd_p == 1, ("gate descriptor for vector %d not present",
+           vector));
+       KASSERT(gd->gd_type == SDT_SYSIGT, ("gate descriptor for vector %d "
+           "has invalid type %d", vector, gd->gd_type));
+       KASSERT(gd->gd_dpl == SEL_KPL, ("gate descriptor for vector %d "
+           "has invalid dpl %d", vector, gd->gd_dpl));
+       KASSERT(gd->gd_selector == GSEL(GCODE_SEL, SEL_KPL), ("gate descriptor "
+           "for vector %d has invalid selector %d", vector, gd->gd_selector));
+       KASSERT(gd->gd_ist == 0, ("gate descriptor for vector %d has invalid "
+           "IST %d", vector, gd->gd_ist));
+
+       func = ((long)gd->gd_hioffset << 16 | gd->gd_looffset);
+       vmx_call_isr(func);
+}
+
 static int
 vmx_setup_cr_shadow(int which, struct vmcs *vmcs, uint32_t initial)
 {
@@ -997,7 +1023,7 @@ vmx_inject_nmi(struct vmx *vmx, int vcpu
         * Inject the virtual NMI. The vector must be the NMI IDT entry
         * or the VMCS entry check will fail.
         */
-       info = VMCS_INTERRUPTION_INFO_NMI | VMCS_INTERRUPTION_INFO_VALID;
+       info = VMCS_INTR_INFO_NMI | VMCS_INTR_INFO_VALID;
        info |= IDT_NMI;
        vmcs_write(VMCS_ENTRY_INTR_INFO, info);
 
@@ -1035,7 +1061,7 @@ vmx_inject_interrupts(struct vmx *vmx, i
         * because of a pending AST.
         */
        info = vmcs_read(VMCS_ENTRY_INTR_INFO);
-       if (info & VMCS_INTERRUPTION_INFO_VALID)
+       if (info & VMCS_INTR_INFO_VALID)
                return;
 
        /*
@@ -1066,7 +1092,7 @@ vmx_inject_interrupts(struct vmx *vmx, i
                goto cantinject;
 
        /* Inject the interrupt */
-       info = VMCS_INTERRUPTION_INFO_HW_INTR | VMCS_INTERRUPTION_INFO_VALID;
+       info = VMCS_INTR_INFO_HW_INTR | VMCS_INTR_INFO_VALID;
        info |= vector;
        vmcs_write(VMCS_ENTRY_INTR_INFO, info);
 
@@ -1376,7 +1402,7 @@ vmx_exit_process(struct vmx *vmx, int vc
        int error, handled;
        struct vmxctx *vmxctx;
        struct vlapic *vlapic;
-       uint32_t eax, ecx, edx, idtvec_info, idtvec_err, reason;
+       uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, reason;
        uint64_t qual, gpa;
        bool retu;
 
@@ -1487,6 +1513,11 @@ vmx_exit_process(struct vmx *vmx, int vc
                 * host interrupt handler in the VM's softc. We will inject
                 * this virtual interrupt during the subsequent VM enter.
                 */
+               intr_info = vmcs_read(VMCS_EXIT_INTR_INFO);
+               KASSERT((intr_info & VMCS_INTR_INFO_VALID) != 0 &&
+                   VMCS_INTR_INFO_TYPE(intr_info) == 0,
+                   ("VM exit interruption info invalid: %#x", intr_info));
+               vmx_trigger_hostintr(intr_info & 0xff);
 
                /*
                 * This is special. We want to treat this as an 'handled'
@@ -1945,11 +1976,11 @@ vmx_inject(void *arg, int vcpu, int type
        if (error)
                return (error);
 
-       if (info & VMCS_INTERRUPTION_INFO_VALID)
+       if (info & VMCS_INTR_INFO_VALID)
                return (EAGAIN);
 
        info = vector | (type_map[type] << 8) | (code_valid ? 1 << 11 : 0);
-       info |= VMCS_INTERRUPTION_INFO_VALID;
+       info |= VMCS_INTR_INFO_VALID;
        error = vmcs_setreg(vmcs, 0, VMCS_IDENT(VMCS_ENTRY_INTR_INFO), info);
        if (error != 0)
                return (error);

Modified: head/sys/amd64/vmm/intel/vmx.h
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.h      Sat Jan 11 01:50:45 2014        
(r260530)
+++ head/sys/amd64/vmm/intel/vmx.h      Sat Jan 11 03:14:05 2014        
(r260531)
@@ -115,6 +115,7 @@ CTASSERT((offsetof(struct vmx, guest_msr
 #define        VMX_INVEPT_ERROR        3
 int    vmx_enter_guest(struct vmxctx *ctx, int launched);
 void   vmx_exit_guest(void);
+void   vmx_call_isr(uintptr_t entry);
 
 u_long vmx_fix_cr0(u_long cr0);
 u_long vmx_fix_cr4(u_long cr4);

Modified: head/sys/amd64/vmm/intel/vmx_genassym.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx_genassym.c     Sat Jan 11 01:50:45 2014        
(r260530)
+++ head/sys/amd64/vmm/intel/vmx_genassym.c     Sat Jan 11 03:14:05 2014        
(r260531)
@@ -84,3 +84,6 @@ ASSYM(PC_CPUID, offsetof(struct pcpu, pc
 
 ASSYM(PM_ACTIVE, offsetof(struct pmap, pm_active));
 ASSYM(PM_EPTGEN, offsetof(struct pmap, pm_eptgen));
+
+ASSYM(KERNEL_SS, GSEL(GDATA_SEL, SEL_KPL));
+ASSYM(KERNEL_CS, GSEL(GCODE_SEL, SEL_KPL));

Modified: head/sys/amd64/vmm/intel/vmx_support.S
==============================================================================
--- head/sys/amd64/vmm/intel/vmx_support.S      Sat Jan 11 01:50:45 2014        
(r260530)
+++ head/sys/amd64/vmm/intel/vmx_support.S      Sat Jan 11 03:14:05 2014        
(r260531)
@@ -234,3 +234,21 @@ ENTRY(vmx_exit_guest)
        movl    $VMX_GUEST_VMEXIT, %eax
        ret
 END(vmx_exit_guest)
+
+/*
+ * %rdi = interrupt handler entry point
+ *
+ * Calling sequence described in the "Instruction Set Reference" for the "INT"
+ * instruction in Intel SDM, Vol 2.
+ */
+ENTRY(vmx_call_isr)
+       mov     %rsp, %r11                      /* save %rsp */
+       and     $~0xf, %rsp                     /* align on 16-byte boundary */
+       pushq   $KERNEL_SS                      /* %ss */
+       pushq   %r11                            /* %rsp */
+       pushfq                                  /* %rflags */
+       pushq   $KERNEL_CS                      /* %cs */
+       cli                                     /* disable interrupts */
+       callq   *%rdi                           /* push %rip and call isr */
+       ret
+END(vmx_call_isr)
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to