Changeset View
Changeset View
Standalone View
Standalone View
sys/amd64/vmm/intel/vmx.c
Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | #define PROCBASED_CTLS_ZERO_SETTING \ | ||||
(PROCBASED_CR3_LOAD_EXITING | \ | (PROCBASED_CR3_LOAD_EXITING | \ | ||||
PROCBASED_CR3_STORE_EXITING | \ | PROCBASED_CR3_STORE_EXITING | \ | ||||
PROCBASED_IO_BITMAPS) | PROCBASED_IO_BITMAPS) | ||||
#define PROCBASED_CTLS2_ONE_SETTING PROCBASED2_ENABLE_EPT | #define PROCBASED_CTLS2_ONE_SETTING PROCBASED2_ENABLE_EPT | ||||
#define PROCBASED_CTLS2_ZERO_SETTING 0 | #define PROCBASED_CTLS2_ZERO_SETTING 0 | ||||
#define VM_EXIT_CTLS_ONE_SETTING \ | #define VM_EXIT_CTLS_ONE_SETTING \ | ||||
(VM_EXIT_HOST_LMA | \ | (VM_EXIT_SAVE_DEBUG_CONTROLS | \ | ||||
VM_EXIT_HOST_LMA | \ | |||||
VM_EXIT_SAVE_EFER | \ | VM_EXIT_SAVE_EFER | \ | ||||
VM_EXIT_LOAD_EFER | \ | VM_EXIT_LOAD_EFER | \ | ||||
VM_EXIT_ACKNOWLEDGE_INTERRUPT) | VM_EXIT_ACKNOWLEDGE_INTERRUPT) | ||||
#define VM_EXIT_CTLS_ZERO_SETTING VM_EXIT_SAVE_DEBUG_CONTROLS | #define VM_EXIT_CTLS_ZERO_SETTING 0 | ||||
#define VM_ENTRY_CTLS_ONE_SETTING (VM_ENTRY_LOAD_EFER) | #define VM_ENTRY_CTLS_ONE_SETTING \ | ||||
(VM_ENTRY_LOAD_DEBUG_CONTROLS | \ | |||||
VM_ENTRY_LOAD_EFER) | |||||
#define VM_ENTRY_CTLS_ZERO_SETTING \ | #define VM_ENTRY_CTLS_ZERO_SETTING \ | ||||
(VM_ENTRY_LOAD_DEBUG_CONTROLS | \ | (VM_ENTRY_INTO_SMM | \ | ||||
VM_ENTRY_INTO_SMM | \ | |||||
VM_ENTRY_DEACTIVATE_DUAL_MONITOR) | VM_ENTRY_DEACTIVATE_DUAL_MONITOR) | ||||
#define HANDLED 1 | #define HANDLED 1 | ||||
#define UNHANDLED 0 | #define UNHANDLED 0 | ||||
static MALLOC_DEFINE(M_VMX, "vmx", "vmx"); | static MALLOC_DEFINE(M_VMX, "vmx", "vmx"); | ||||
static MALLOC_DEFINE(M_VLAPIC, "vlapic", "vlapic"); | static MALLOC_DEFINE(M_VLAPIC, "vlapic", "vlapic"); | ||||
▲ Show 20 Lines • Show All 789 Lines • ▼ Show 20 Lines | for (i = 0; i < VM_MAXCPU; i++) { | ||||
/* exception bitmap */ | /* exception bitmap */ | ||||
if (vcpu_trace_exceptions(vm, i)) | if (vcpu_trace_exceptions(vm, i)) | ||||
exc_bitmap = 0xffffffff; | exc_bitmap = 0xffffffff; | ||||
else | else | ||||
exc_bitmap = 1 << IDT_MC; | exc_bitmap = 1 << IDT_MC; | ||||
error += vmwrite(VMCS_EXCEPTION_BITMAP, exc_bitmap); | error += vmwrite(VMCS_EXCEPTION_BITMAP, exc_bitmap); | ||||
vmx->ctx[i].guest_dr6 = 0xffff0ff0; | |||||
error += vmwrite(VMCS_GUEST_DR7, 0x400); | |||||
if (virtual_interrupt_delivery) { | if (virtual_interrupt_delivery) { | ||||
error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS); | error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS); | ||||
error += vmwrite(VMCS_VIRTUAL_APIC, | error += vmwrite(VMCS_VIRTUAL_APIC, | ||||
vtophys(&vmx->apic_page[i])); | vtophys(&vmx->apic_page[i])); | ||||
error += vmwrite(VMCS_EOI_EXIT0, 0); | error += vmwrite(VMCS_EOI_EXIT0, 0); | ||||
error += vmwrite(VMCS_EOI_EXIT1, 0); | error += vmwrite(VMCS_EOI_EXIT1, 0); | ||||
error += vmwrite(VMCS_EOI_EXIT2, 0); | error += vmwrite(VMCS_EOI_EXIT2, 0); | ||||
error += vmwrite(VMCS_EOI_EXIT3, 0); | error += vmwrite(VMCS_EOI_EXIT3, 0); | ||||
▲ Show 20 Lines • Show All 1,640 Lines • ▼ Show 20 Lines | vmx_exit_handle_nmi(struct vmx *vmx, int vcpuid, struct vm_exit *vmexit) | ||||
if ((intr_info & VMCS_INTR_T_MASK) == VMCS_INTR_T_NMI) { | if ((intr_info & VMCS_INTR_T_MASK) == VMCS_INTR_T_NMI) { | ||||
KASSERT((intr_info & 0xff) == IDT_NMI, ("VM exit due " | KASSERT((intr_info & 0xff) == IDT_NMI, ("VM exit due " | ||||
"to NMI has invalid vector: %#x", intr_info)); | "to NMI has invalid vector: %#x", intr_info)); | ||||
VCPU_CTR0(vmx->vm, vcpuid, "Vectoring to NMI handler"); | VCPU_CTR0(vmx->vm, vcpuid, "Vectoring to NMI handler"); | ||||
__asm __volatile("int $2"); | __asm __volatile("int $2"); | ||||
} | } | ||||
} | } | ||||
static __inline void | |||||
vmx_dr_enter_guest(struct vmxctx *vmxctx) | |||||
{ | |||||
register_t rflags; | |||||
/* Save host control debug registers. */ | |||||
vmxctx->host_dr7 = rdr7(); | |||||
vmxctx->host_debugctl = rdmsr(MSR_DEBUGCTLMSR); | |||||
/* | |||||
* Disable debugging in DR7 and DEBUGCTL to avoid triggering | |||||
* exceptions in the host based on the guest DRx values. The | |||||
* guest DR7 and DEBUGCTL are saved/restored in the VMCS. | |||||
*/ | |||||
load_dr7(0); | |||||
wrmsr(MSR_DEBUGCTLMSR, 0); | |||||
/* | |||||
* Disable single stepping the kernel to avoid corrupting the | |||||
* guest DR6. A debugger might still be able to corrupt the | |||||
* guest DR6 by setting a breakpoint after this point and then | |||||
* single stepping. | |||||
*/ | |||||
rflags = read_rflags(); | |||||
vmxctx->host_tf = rflags & PSL_T; | |||||
write_rflags(rflags & ~PSL_T); | |||||
/* Save host debug registers. */ | |||||
vmxctx->host_dr0 = rdr0(); | |||||
vmxctx->host_dr1 = rdr1(); | |||||
vmxctx->host_dr2 = rdr2(); | |||||
vmxctx->host_dr3 = rdr3(); | |||||
vmxctx->host_dr6 = rdr6(); | |||||
/* Restore guest debug registers. */ | |||||
load_dr0(vmxctx->guest_dr0); | |||||
load_dr1(vmxctx->guest_dr1); | |||||
load_dr2(vmxctx->guest_dr2); | |||||
load_dr3(vmxctx->guest_dr3); | |||||
load_dr6(vmxctx->guest_dr6); | |||||
} | |||||
static __inline void | |||||
vmx_dr_leave_guest(struct vmxctx *vmxctx) | |||||
{ | |||||
/* Save guest debug registers. */ | |||||
vmxctx->guest_dr0 = rdr0(); | |||||
vmxctx->guest_dr1 = rdr1(); | |||||
vmxctx->guest_dr2 = rdr2(); | |||||
vmxctx->guest_dr3 = rdr3(); | |||||
vmxctx->guest_dr6 = rdr6(); | |||||
/* | |||||
* Restore host debug registers. Restore DR7, DEBUGCTL, and | |||||
* PSL_T last. | |||||
*/ | |||||
load_dr0(vmxctx->host_dr0); | |||||
load_dr1(vmxctx->host_dr1); | |||||
load_dr2(vmxctx->host_dr2); | |||||
load_dr3(vmxctx->host_dr3); | |||||
load_dr6(vmxctx->host_dr6); | |||||
wrmsr(MSR_DEBUGCTLMSR, vmxctx->host_debugctl); | |||||
load_dr7(vmxctx->host_dr7); | |||||
write_rflags(read_rflags() | vmxctx->host_tf); | |||||
} | |||||
static int | static int | ||||
vmx_run(void *arg, int vcpu, register_t rip, pmap_t pmap, | vmx_run(void *arg, int vcpu, register_t rip, pmap_t pmap, | ||||
struct vm_eventinfo *evinfo) | struct vm_eventinfo *evinfo) | ||||
{ | { | ||||
int rc, handled, launched; | int rc, handled, launched; | ||||
struct vmx *vmx; | struct vmx *vmx; | ||||
struct vm *vm; | struct vm *vm; | ||||
struct vmxctx *vmxctx; | struct vmxctx *vmxctx; | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | if (vcpu_should_yield(vm, vcpu)) { | ||||
enable_intr(); | enable_intr(); | ||||
vm_exit_astpending(vmx->vm, vcpu, rip); | vm_exit_astpending(vmx->vm, vcpu, rip); | ||||
vmx_astpending_trace(vmx, vcpu, rip); | vmx_astpending_trace(vmx, vcpu, rip); | ||||
handled = HANDLED; | handled = HANDLED; | ||||
break; | break; | ||||
} | } | ||||
vmx_run_trace(vmx, vcpu); | vmx_run_trace(vmx, vcpu); | ||||
vmx_dr_enter_guest(vmxctx); | |||||
rc = vmx_enter_guest(vmxctx, vmx, launched); | rc = vmx_enter_guest(vmxctx, vmx, launched); | ||||
vmx_dr_leave_guest(vmxctx); | |||||
/* Collect some information for VM exit processing */ | /* Collect some information for VM exit processing */ | ||||
vmexit->rip = rip = vmcs_guest_rip(); | vmexit->rip = rip = vmcs_guest_rip(); | ||||
vmexit->inst_length = vmexit_instruction_length(); | vmexit->inst_length = vmexit_instruction_length(); | ||||
vmexit->u.vmx.exit_reason = exit_reason = vmcs_exit_reason(); | vmexit->u.vmx.exit_reason = exit_reason = vmcs_exit_reason(); | ||||
vmexit->u.vmx.exit_qualification = vmcs_exit_qualification(); | vmexit->u.vmx.exit_qualification = vmcs_exit_qualification(); | ||||
/* Update 'nextrip' */ | /* Update 'nextrip' */ | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | vmxctx_regptr(struct vmxctx *vmxctx, int reg) | ||||
case VM_REG_GUEST_R13: | case VM_REG_GUEST_R13: | ||||
return (&vmxctx->guest_r13); | return (&vmxctx->guest_r13); | ||||
case VM_REG_GUEST_R14: | case VM_REG_GUEST_R14: | ||||
return (&vmxctx->guest_r14); | return (&vmxctx->guest_r14); | ||||
case VM_REG_GUEST_R15: | case VM_REG_GUEST_R15: | ||||
return (&vmxctx->guest_r15); | return (&vmxctx->guest_r15); | ||||
case VM_REG_GUEST_CR2: | case VM_REG_GUEST_CR2: | ||||
return (&vmxctx->guest_cr2); | return (&vmxctx->guest_cr2); | ||||
case VM_REG_GUEST_DR0: | |||||
return (&vmxctx->guest_dr0); | |||||
case VM_REG_GUEST_DR1: | |||||
return (&vmxctx->guest_dr1); | |||||
case VM_REG_GUEST_DR2: | |||||
return (&vmxctx->guest_dr2); | |||||
case VM_REG_GUEST_DR3: | |||||
return (&vmxctx->guest_dr3); | |||||
case VM_REG_GUEST_DR6: | |||||
return (&vmxctx->guest_dr6); | |||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
static int | static int | ||||
vmxctx_getreg(struct vmxctx *vmxctx, int reg, uint64_t *retval) | vmxctx_getreg(struct vmxctx *vmxctx, int reg, uint64_t *retval) | ||||
▲ Show 20 Lines • Show All 663 Lines • Show Last 20 Lines |