svn commit: r260531 - head/sys/amd64/vmm/intel
Neel Natu
neel at FreeBSD.org
Sat Jan 11 03:14:07 UTC 2014
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)
More information about the svn-src-all
mailing list