#include <palacios/vmx_ctrl_regs.h>
#include <palacios/vmx_assist.h>
#include <palacios/vmm_halt.h>
+#include <palacios/vmx_ept.h>
-#ifdef CONFIG_TELEMETRY
-#include <palacios/vmm_telemetry.h>
+#ifndef V3_CONFIG_DEBUG_VMX
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
#endif
-
-
+#ifdef V3_CONFIG_TELEMETRY
+#include <palacios/vmm_telemetry.h>
+#endif
/* At this point the GPRs are already copied into the guest_info state */
int v3_handle_vmx_exit(struct guest_info * info, struct vmx_exit_info * exit_info) {
- struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data);
+ struct vmx_basic_exit_info * basic_info = (struct vmx_basic_exit_info *)&(exit_info->exit_reason);
/*
PrintError("Handling VMEXIT: %s (%u), %lu (0x%lx)\n",
v3_print_vmcs();
*/
-#ifdef CONFIG_TELEMETRY
- if (info->enable_telemetry) {
+
+
+ if (basic_info->entry_error == 1) {
+ switch (basic_info->reason) {
+ case VMEXIT_INVALID_GUEST_STATE:
+ PrintError("VM Entry failed due to invalid guest state\n");
+ PrintError("Printing VMCS: (NOTE: This VMCS may not belong to the correct guest)\n");
+ v3_print_vmcs();
+ break;
+ case VMEXIT_INVALID_MSR_LOAD:
+ PrintError("VM Entry failed due to error loading MSRs\n");
+ break;
+ default:
+ PrintError("Entry failed for unknown reason (%d)\n", basic_info->reason);
+ break;
+ }
+
+ return -1;
+ }
+
+
+#ifdef V3_CONFIG_TELEMETRY
+ if (info->vm_info->enable_telemetry) {
v3_telemetry_start_exit(info);
}
#endif
- switch (exit_info->exit_reason) {
+ switch (basic_info->reason) {
case VMEXIT_INFO_EXCEPTION_OR_NMI: {
pf_error_t error_code = *(pf_error_t *)&(exit_info->int_err);
// JRL: Change "0x0e" to a macro value
- if ((uint8_t)exit_info->int_info == 0x0e) {
-#ifdef CONFIG_DEBUG_SHADOW_PAGING
+ if ((uint8_t)exit_info->int_info == 14) {
+#ifdef V3_CONFIG_DEBUG_SHADOW_PAGING
PrintDebug("Page Fault at %p error_code=%x\n", (void *)exit_info->exit_qual, *(uint32_t *)&error_code);
#endif
PrintError("Error handling shadow page fault\n");
return -1;
}
+
} else {
PrintError("Page fault in unimplemented paging mode\n");
return -1;
}
+ } else if ((uint8_t)exit_info->int_info == 2) {
+ // NMI. Don't do anything
+ V3_Print("NMI Exception Received\n");
} else {
PrintError("Unknown exception: 0x%x\n", (uint8_t)exit_info->int_info);
v3_print_GPRs(info);
break;
}
+ case VMEXIT_EPT_VIOLATION: {
+ struct ept_exit_qual * ept_qual = (struct ept_exit_qual *)&(exit_info->exit_qual);
+
+ if (v3_handle_ept_fault(info, exit_info->ept_fault_addr, ept_qual) == -1) {
+ PrintError("Error handling EPT fault\n");
+ return -1;
+ }
+
+ break;
+ }
case VMEXIT_INVLPG:
if (info->shdw_pg_mode == SHADOW_PAGING) {
if (v3_handle_shadow_invlpg(info) == -1) {
}
break;
+
+ case VMEXIT_RDTSC:
+#ifdef V3_CONFIG_DEBUG_TIME
+ PrintDebug("RDTSC\n");
+#endif
+ if (v3_handle_rdtsc(info) == -1) {
+ PrintError("Error Handling RDTSC instruction\n");
+ return -1;
+ }
+
+ break;
+
case VMEXIT_CPUID:
if (v3_handle_cpuid(info) == -1) {
PrintError("Error Handling CPUID instruction\n");
if (io_qual->dir == 0) {
if (io_qual->string) {
- if (v3_handle_vmx_io_outs(info) == -1) {
+ if (v3_handle_vmx_io_outs(info, exit_info) == -1) {
PrintError("Error in outs IO handler\n");
return -1;
}
} else {
- if (v3_handle_vmx_io_out(info) == -1) {
+ if (v3_handle_vmx_io_out(info, exit_info) == -1) {
PrintError("Error in out IO handler\n");
return -1;
}
}
} else {
if (io_qual->string) {
- if(v3_handle_vmx_io_ins(info) == -1) {
+ if(v3_handle_vmx_io_ins(info, exit_info) == -1) {
PrintError("Error in ins IO handler\n");
return -1;
}
} else {
- if (v3_handle_vmx_io_in(info) == -1) {
+ if (v3_handle_vmx_io_in(info, exit_info) == -1) {
PrintError("Error in in IO handler\n");
return -1;
}
return -1;
}
break;
+ case 4:
+ //PrintDebug("Handling CR4 Access\n");
+ if (v3_vmx_handle_cr4_access(info, cr_qual) == -1) {
+ PrintError("Error in CR4 access handler\n");
+ return -1;
+ }
+ break;
default:
PrintError("Unhandled CR access: %d\n", cr_qual->cr_id);
return -1;
}
- info->rip += exit_info->instr_len;
+ // TODO: move RIP increment into all of the above individual CR
+ // handlers, not just v3_vmx_handle_cr4_access()
+ if (cr_qual->cr_id != 4)
+ info->rip += exit_info->instr_len;
break;
}
}
break;
+
+
+
case VMEXIT_PAUSE:
// Handled as NOP
info->rip += 2;
// Interrupts are handled outside switch
break;
case VMEXIT_INTR_WINDOW:
-
- 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
-
+ // This is handled in the atomic part of the vmx code,
+ // not in the generic (interruptable) vmx handler
break;
+
+
default:
PrintError("Unhandled VMEXIT: %s (%u), %lu (0x%lx)\n",
- v3_vmx_exit_code_to_str(exit_info->exit_reason),
- exit_info->exit_reason,
+ v3_vmx_exit_code_to_str(basic_info->reason),
+ basic_info->reason,
exit_info->exit_qual, exit_info->exit_qual);
return -1;
}
-#ifdef CONFIG_TELEMETRY
- if (info->enable_telemetry) {
+
+#ifdef V3_CONFIG_TELEMETRY
+ if (info->vm_info->enable_telemetry) {
v3_telemetry_end_exit(info, exit_info->exit_reason);
}
#endif
+
return 0;
}
static const char VMEXIT_IO_INSTR_STR[] = "VMEXIT_IO_INSTR";
static const char VMEXIT_RDMSR_STR[] = "VMEXIT_RDMSR";
static const char VMEXIT_WRMSR_STR[] = "VMEXIT_WRMSR";
-static const char VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR[] = "VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE";
-static const char VMEXIT_ENTRY_FAIL_MSR_LOAD_STR[] = "VMEXIT_ENTRY_FAIL_MSR_LOAD";
+static const char VMEXIT_INVALID_GUEST_STATE_STR[] = "VMEXIT_INVALID_GUEST_STATE";
+static const char VMEXIT_INVALID_MSR_LOAD_STR[] = "VMEXIT_INVALID_MSR_LOAD";
static const char VMEXIT_MWAIT_STR[] = "VMEXIT_MWAIT";
static const char VMEXIT_MONITOR_STR[] = "VMEXIT_MONITOR";
static const char VMEXIT_PAUSE_STR[] = "VMEXIT_PAUSE";
-static const char VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR[] = "VMEXIT_ENTRY_FAILURE_MACHINE_CHECK";
+static const char VMEXIT_INVALID_MACHINE_CHECK_STR[] = "VMEXIT_INVALIDE_MACHINE_CHECK";
static const char VMEXIT_TPR_BELOW_THRESHOLD_STR[] = "VMEXIT_TPR_BELOW_THRESHOLD";
static const char VMEXIT_APIC_STR[] = "VMEXIT_APIC";
static const char VMEXIT_GDTR_IDTR_STR[] = "VMEXIT_GDTR_IDTR";
return VMEXIT_RDMSR_STR;
case VMEXIT_WRMSR:
return VMEXIT_WRMSR_STR;
- case VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE:
- return VMEXIT_ENTRY_FAIL_INVALID_GUEST_STATE_STR;
- case VMEXIT_ENTRY_FAIL_MSR_LOAD:
- return VMEXIT_ENTRY_FAIL_MSR_LOAD_STR;
+ case VMEXIT_INVALID_GUEST_STATE:
+ return VMEXIT_INVALID_GUEST_STATE_STR;
+ case VMEXIT_INVALID_MSR_LOAD:
+ return VMEXIT_INVALID_MSR_LOAD_STR;
case VMEXIT_MWAIT:
return VMEXIT_MWAIT_STR;
case VMEXIT_MONITOR:
return VMEXIT_MONITOR_STR;
case VMEXIT_PAUSE:
return VMEXIT_PAUSE_STR;
- case VMEXIT_ENTRY_FAILURE_MACHINE_CHECK:
- return VMEXIT_ENTRY_FAILURE_MACHINE_CHECK_STR;
+ case VMEXIT_INVALID_MACHINE_CHECK:
+ return VMEXIT_INVALID_MACHINE_CHECK_STR;
case VMEXIT_TPR_BELOW_THRESHOLD:
return VMEXIT_TPR_BELOW_THRESHOLD_STR;
case VMEXIT_APIC: