Date: Sat, 11 Jan 2014 03:14:06 +0000 (UTC) From: Neel Natu <neel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r260531 - head/sys/amd64/vmm/intel Message-ID: <201401110314.s0B3E647033659@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201401110314.s0B3E647033659>