#include <palacios/vmx_io.h>
#include <palacios/vmx_msr.h>
+#include <palacios/vmx_hw_info.h>
#ifndef CONFIG_DEBUG_VMX
#undef PrintDebug
#endif
-static addr_t host_vmcs_ptrs[CONFIG_MAX_CPUS] = { [0 ... CONFIG_MAX_CPUS - 1] = 0};
+/* These fields contain the hardware feature sets supported by the local CPU */
+static struct vmx_hw_info hw_info;
+
+
static addr_t active_vmcs_ptrs[CONFIG_MAX_CPUS] = { [0 ... CONFIG_MAX_CPUS - 1] = 0};
+static addr_t host_vmcs_ptrs[CONFIG_MAX_CPUS] = { [0 ... CONFIG_MAX_CPUS - 1] = 0};
extern int v3_vmx_launch(struct v3_gprs * vm_regs, struct guest_info * info, struct v3_ctrl_regs * ctrl_regs);
extern int v3_vmx_resume(struct v3_gprs * vm_regs, struct guest_info * info, struct v3_ctrl_regs * ctrl_regs);
static int inline check_vmcs_write(vmcs_field_t field, addr_t val) {
int ret = 0;
- ret = vmcs_write(field,val);
+ ret = vmcs_write(field, val);
if (ret != VMX_SUCCESS) {
PrintError("VMWRITE error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
return ret;
}
-#if 0
-// For the 32 bit reserved bit fields
-// MB1s are in the low 32 bits, MBZs are in the high 32 bits of the MSR
-static uint32_t sanitize_bits1(uint32_t msr_num, uint32_t val) {
- v3_msr_t mask_msr;
-
- PrintDebug("sanitize_bits1 (MSR:%x)\n", msr_num);
- v3_get_msr(msr_num, &mask_msr.hi, &mask_msr.lo);
-
- PrintDebug("MSR %x = %x : %x \n", msr_num, mask_msr.hi, mask_msr.lo);
-
- val |= mask_msr.lo;
- val |= mask_msr.hi;
-
- return val;
-}
-
-
-
-static addr_t sanitize_bits2(uint32_t msr_num0, uint32_t msr_num1, addr_t val) {
- v3_msr_t msr0, msr1;
- addr_t msr0_val, msr1_val;
-
- PrintDebug("sanitize_bits2 (MSR0=%x, MSR1=%x)\n", msr_num0, msr_num1);
-
- v3_get_msr(msr_num0, &msr0.hi, &msr0.lo);
- v3_get_msr(msr_num1, &msr1.hi, &msr1.lo);
-
- // This generates a mask that is the natural bit width of the CPU
- msr0_val = msr0.value;
- msr1_val = msr1.value;
-
- PrintDebug("MSR %x = %p, %x = %p \n", msr_num0, (void*)msr0_val, msr_num1, (void*)msr1_val);
-
- val |= msr0_val;
- val |= msr1_val;
-
- return val;
-}
-
-
-
-#endif
static addr_t allocate_vmcs() {
- reg_ex_t msr;
struct vmcs_data * vmcs_page = NULL;
PrintDebug("Allocating page\n");
vmcs_page = (struct vmcs_data *)V3_VAddr(V3_AllocPages(1));
memset(vmcs_page, 0, 4096);
- v3_get_msr(VMX_BASIC_MSR, &(msr.e_reg.high), &(msr.e_reg.low));
-
- vmcs_page->revision = ((struct vmx_basic_msr*)&msr)->revision;
- PrintDebug("VMX Revision: 0x%x\n",vmcs_page->revision);
+ vmcs_page->revision = hw_info.basic_info.revision;
+ PrintDebug("VMX Revision: 0x%x\n", vmcs_page->revision);
return (addr_t)V3_PAddr((void *)vmcs_page);
}
// reenable global interrupts for vm state initialization now
// that the vm state is initialized. If another VM kicks us off,
// it'll update our vmx state so that we know to reload ourself
- v3_disable_ints();
+ v3_enable_ints();
return 0;
}
// disable global interrupts for vm state transition
v3_disable_ints();
+
+ if (active_vmcs_ptrs[V3_Get_CPU()] != vmx_info->vmcs_ptr_phys) {
+ vmcs_load(vmx_info->vmcs_ptr_phys);
+ active_vmcs_ptrs[V3_Get_CPU()] = vmx_info->vmcs_ptr_phys;
+ }
+
+
v3_vmx_restore_vmcs(info);
check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high);
check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low);
- if (active_vmcs_ptrs[V3_Get_CPU()] != vmx_info->vmcs_ptr_phys) {
- vmcs_load(vmx_info->vmcs_ptr_phys);
- active_vmcs_ptrs[V3_Get_CPU()] = vmx_info->vmcs_ptr_phys;
- }
if (vmx_info->state == VMX_UNLAUNCHED) {
vmx_info->state = VMX_LAUNCHED;
update_irq_exit_state(info);
#endif
- // Handle any exits needed still in the atomic section
- if (v3_handle_vmx_exit(info, &exit_info) == -1) {
- PrintError("Error in atomic VMX exit handler\n");
- return -1;
+ if (exit_info.exit_reason == VMEXIT_INTR_WINDOW) {
+ // This is a special case whose only job is to inject an interrupt
+ vmcs_read(VMCS_PROC_CTRLS, &(vmx_info->pri_proc_ctrls.value));
+ vmx_info->pri_proc_ctrls.int_wndw_exit = 0;
+ vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value);
+
+#ifdef CONFIG_DEBUG_INTERRUPTS
+ PrintDebug("Interrupts available again! (RIP=%llx)\n", info->rip);
+#endif
}
// reenable global interrupts after vm exit
}
+
+
+#define VMX_FEATURE_CONTROL_MSR 0x0000003a
+#define CPUID_VMX_FEATURES 0x00000005 /* LOCK and VMXON */
+#define CPUID_1_ECX_VTXFLAG 0x00000020
+
int v3_is_vmx_capable() {
v3_msr_t feature_msr;
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
PrintDebug("MSRREGlow: 0x%.8x\n", feature_msr.lo);
- if ((feature_msr.lo & FEATURE_CONTROL_VALID) != FEATURE_CONTROL_VALID) {
+ if ((feature_msr.lo & CPUID_VMX_FEATURES) != CPUID_VMX_FEATURES) {
PrintDebug("VMX is locked -- enable in the BIOS\n");
return 0;
}
return 1;
}
-static int has_vmx_nested_paging() {
- return 0;
-}
-void v3_init_vmx_cpu(int cpu_id) {
- extern v3_cpu_arch_t v3_cpu_types[];
- struct v3_msr tmp_msr;
- uint64_t ret = 0;
- v3_get_msr(VMX_CR4_FIXED0_MSR, &(tmp_msr.hi), &(tmp_msr.lo));
-#ifdef __V3_64BIT__
- __asm__ __volatile__ (
- "movq %%cr4, %%rbx;"
- "orq $0x00002000, %%rbx;"
- "movq %%rbx, %0;"
- : "=m"(ret)
- :
- : "%rbx"
- );
-
- if ((~ret & tmp_msr.value) == 0) {
- __asm__ __volatile__ (
- "movq %0, %%cr4;"
- :
- : "q"(ret)
- );
- } else {
- PrintError("Invalid CR4 Settings!\n");
- return;
- }
+void v3_init_vmx_cpu(int cpu_id) {
+ extern v3_cpu_arch_t v3_cpu_types[];
- __asm__ __volatile__ (
- "movq %%cr0, %%rbx; "
- "orq $0x00000020,%%rbx; "
- "movq %%rbx, %%cr0;"
- :
- :
- : "%rbx"
- );
-#elif __V3_32BIT__
- __asm__ __volatile__ (
- "movl %%cr4, %%ecx;"
- "orl $0x00002000, %%ecx;"
- "movl %%ecx, %0;"
- : "=m"(ret)
- :
- : "%ecx"
- );
-
- if ((~ret & tmp_msr.value) == 0) {
- __asm__ __volatile__ (
- "movl %0, %%cr4;"
- :
- : "q"(ret)
- );
- } else {
- PrintError("Invalid CR4 Settings!\n");
- return;
+ if (cpu_id == 0) {
+ if (v3_init_vmx_hw(&hw_info) == -1) {
+ PrintError("Could not initialize VMX hardware features on cpu %d\n", cpu_id);
+ return;
+ }
}
- __asm__ __volatile__ (
- "movl %%cr0, %%ecx; "
- "orl $0x00000020,%%ecx; "
- "movl %%ecx, %%cr0;"
- :
- :
- : "%ecx"
- );
-
-#endif
- //
- // Should check and return Error here....
+ enable_vmx();
// Setup VMXON Region
PrintDebug("VMXON pointer: 0x%p\n", (void *)host_vmcs_ptrs[cpu_id]);
- if (v3_enable_vmx(host_vmcs_ptrs[cpu_id]) == VMX_SUCCESS) {
+ if (vmx_on(host_vmcs_ptrs[cpu_id]) == VMX_SUCCESS) {
PrintDebug("VMX Enabled\n");
} else {
PrintError("VMX initialization failure\n");
}
- if (has_vmx_nested_paging() == 1) {
- v3_cpu_types[cpu_id] = V3_VMX_EPT_CPU;
- } else {
- v3_cpu_types[cpu_id] = V3_VMX_CPU;
- }
+ v3_cpu_types[cpu_id] = V3_VMX_CPU;
+
}