The purpose of this option is to allow features under development to be committed to the mainline
to more easily track changes and provide access to multiple developers
- config VNET
- depends on EXPERIMENTAL
- bool "Enable Vnet in Palacios"
- default n
- help
- Enable the Vnet in Palacios
-
+
+config INSPECTOR
+ bool "Enable VM inspection"
+ depends on EXPERIMENTAL
+ default n
+ help
+ Enable inspection framework for vm internal state
+
- config SW_INTERRUPTS
- bool "Enable interception and hooking of software interrupts"
- depends on EXPERIMENTAL
- default n
- help
- This feature will cause the VMM to intercept the execution
- of software interrupts (i.e. the INTn instruction) and enable
- any INT vector to be hooked
-
- config SWINTR_PASSTHROUGH
- bool "Hook all unhandled sofware interrupts for passthrough"
- depends on SW_INTERRUPTS
- default n
- help
- If enabled, this will cause all software interrupts
- (INT instruction vectors) to be hooked for passthrough.
- May reduce performance but useful for debugging.
-
- config SYSCALL_HIJACK
- bool "Enable System Call Hijacking"
- depends on SW_INTERRUPTS
- default n
- help
- Enable the VMM to hijack system calls executed by the guest.
- If enabled, the VMM will hook execution of INT 80
- (support for Fast-System Calls coming soon)
-
- config SYSCALL_PASSTHROUGH
- bool "Hook all unhandled system calls for passthrough"
- depends on SYSCALL_HIJACK
- default n
- help
- If enabled, this option will cause all system calls
- that are not explicitly hooked to be hooked for
- passthrough. This is useful for debugging.
-
- config HIJACK_SYSCALL_MSR
- bool "Intercept Syscall-related MSR reads & writes"
- depends on SYSCALL_HIJACK
- default n
- help
- Allow the VMM to intercept reads and writes to MSRs
- related to SYSCALL and SYSENTER instructions. Specifically,
- it will intercept R/W to STAR, CSTAR, and LSTAR.
+
endmenu
endmenu
+ menu "VNET"
+ config VNET
+ bool "Enable Vnet in Palacios"
+ default n
+ help
+ Enable the Vnet in Palacios
+
+ config DEBUG_VNET
+ depends on VNET
+ bool "Enable Vnet Debug in Palacios"
+ default n
+ help
+ Enable the Vnet debug in Palacios
+
+
+ endmenu
menu "Debug configuration"
help
This turns on debugging for the device manager
- config DEBUG_VNET
- depends on EXPERIMENTAL && VNET
- bool "Enable Vnet Debug in Palacios"
- default n
- help
- Enable the Vnet debug in Palacios
+
+config DEBUG_SYSCALL_HIJACK
+ bool "Enable Syscall Hijack Debug in Palacios"
+ default n
+ depends on DEBUG_ON && SYSCALL_HIJACK
+ help
+ Enable Debugging printouts for syscall hijacking
+ code in Palacios
+
+
endmenu
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
#include <palacios/vmm_telemetry.h>
#endif
- #ifdef CONFIG_SYMBIOTIC
+ #ifdef V3_CONFIG_SYMBIOTIC
#include <palacios/vmm_symbiotic.h>
struct v3_sym_core_state;
#endif
- #ifdef CONFIG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_SYSCALL_HIJACK
+#include <palacios/vmm_syscall_hijack.h>
+#include <palacios/vmm_execve_hook.h>
+#endif
+
#include <palacios/vmm_config.h>
/* This structure is how we get exceptions for the guest */
struct v3_excp_state excp_state;
- #ifdef CONFIG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_SYSCALL_HIJACK
+ struct v3_syscall_hook_map sc_hook_map;
+ struct v3_execve_varchunk var_dump;
+ struct v3_exec_hooks exec_hooks;
+#endif
+
v3_cpu_mode_t cpu_mode;
v3_mem_mode_t mem_mode;
uint64_t num_exits;
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
struct v3_core_telemetry core_telem;
#endif
void * decoder_state;
- #ifdef CONFIG_SYMBIOTIC
+ #ifdef V3_CONFIG_SYMBIOTIC
/* Symbiotic state */
struct v3_sym_core_state sym_core_state;
#endif
v3_core_operating_mode_t core_run_state;
/* the logical cpu on which this core runs */
- uint32_t cpu_id;
+ uint32_t pcpu_id;
+
+ /* The virtual core # of this cpu (what the guest sees this core as) */
+ uint32_t vcpu_id;
};
uint32_t mem_align;
struct v3_mem_map mem_map;
- v3_paging_size_t paging_size; // for nested paging
-
struct v3_mem_hooks mem_hooks;
struct v3_shdw_impl_state shdw_impl;
struct v3_extensions extensions;
- #ifdef CONFIG_SYMBIOTIC
+ #ifdef V3_CONFIG_SYMBIOTIC
/* Symbiotic state */
struct v3_sym_vm_state sym_vm_state;
#endif
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
uint_t enable_telemetry;
struct v3_telemetry_state telemetry;
#endif
#define EFER_MSR 0xc0000080
+// KCH: for system-call interposition
- #define STAR_MSR 0xc0000081
- #define LSTAR_MSR 0xc0000082
- #define CSTAR_MSR 0xc0000083
- #define SF_MASK_MSR 0xc0000084
- #define FS_BASE_MSR 0xc0000100
- #define GS_BASE_MSR 0xc0000101
- #define KERN_GS_BASE_MSR 0xc0000102
++#define STAR_MSR 0xc0000081 /* Legacy mode SYSCALL target */
++#define LSTAR_MSR 0xc0000082 /* Long mode SYSCALL target */
++#define CSTAR_MSR 0xc0000083 /* compat mode SYSCALL target */
++#define SF_MASK_MSR 0xc0000084 /* EFLAGS mask for syscall */
++#define FS_BASE_MSR 0xc0000100 /* 64-bit FS base */
++#define GS_BASE_MSR 0xc0000101 /* 64-bit GS base */
++#define KERN_GS_BASE_MSR 0xc0000102 /* swapGS GS shadow */
++
++/* Intel specific */
++#define IA32_SYSENTER_CS_MSR 0x00000174
++#define IA32_SYSENTER_ESP_MSR 0x00000175
++#define IA32_SYSENTER_EIP_MSR 0x00000176
+
struct cr0_real {
uint_t pe : 1;
uint_t mp : 1;
int v3_handle_efer_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data);
int v3_handle_efer_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data);
+int v3_handle_star_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data);
+int v3_handle_star_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data);
+int v3_handle_lstar_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data);
+int v3_handle_lstar_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data);
+int v3_handle_cstar_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data);
+int v3_handle_cstar_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data);
+
++int v3_handle_seeip_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data);
++int v3_handle_seeip_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data);
++
int v3_handle_vm_cr_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data);
int v3_handle_vm_cr_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data);
V3_OP_SETB, V3_OP_SETBE, V3_OP_SETL, V3_OP_SETLE, V3_OP_SETNB,
V3_OP_SETNBE, V3_OP_SETNL, V3_OP_SETNLE, V3_OP_SETNO, V3_OP_SETNP,
V3_OP_SETNS, V3_OP_SETNZ, V3_OP_SETO, V3_OP_SETP, V3_OP_SETS,
- V3_OP_SETZ, V3_OP_MOVS, V3_OP_STOS, V3_OP_MOVZX, V3_OP_MOVSX } v3_op_type_t;
+ V3_OP_SETZ, V3_OP_MOVS, V3_OP_STOS, V3_OP_MOVZX, V3_OP_MOVSX, V3_OP_INT } v3_op_type_t;
typedef enum {INVALID_OPERAND, REG_OPERAND, MEM_OPERAND, IMM_OPERAND} v3_operand_type_t;
} __attribute__((packed));
struct x86_prefixes {
- uint_t lock : 1; // 0xF0
- uint_t repne : 1; // 0xF2
- uint_t repnz : 1; // 0xF2
- uint_t rep : 1; // 0xF3
- uint_t repe : 1; // 0xF3
- uint_t repz : 1; // 0xF3
- uint_t cs_override : 1; // 0x2E
- uint_t ss_override : 1; // 0x36
- uint_t ds_override : 1; // 0x3E
- uint_t es_override : 1; // 0x26
- uint_t fs_override : 1; // 0x64
- uint_t gs_override : 1; // 0x65
- uint_t br_not_taken : 1; // 0x2E
- uint_t br_taken : 1; // 0x3E
- uint_t op_size : 1; // 0x66
- uint_t addr_size : 1; // 0x67
-
- uint_t rex : 1;
+ union {
+ uint32_t val;
+
+ struct {
+ uint_t lock : 1; // 0xF0
+ uint_t repne : 1; // 0xF2
+ uint_t repnz : 1; // 0xF2
+ uint_t rep : 1; // 0xF3
+ uint_t repe : 1; // 0xF3
+ uint_t repz : 1; // 0xF3
+ uint_t cs_override : 1; // 0x2E
+ uint_t ss_override : 1; // 0x36
+ uint_t ds_override : 1; // 0x3E
+ uint_t es_override : 1; // 0x26
+ uint_t fs_override : 1; // 0x64
+ uint_t gs_override : 1; // 0x65
+ uint_t br_not_taken : 1; // 0x2E
+ uint_t br_taken : 1; // 0x3E
+ uint_t op_size : 1; // 0x66
+ uint_t addr_size : 1; // 0x67
+
+ uint_t rex : 1;
- uint_t rex_rm : 1; // REX.B
- uint_t rex_sib_idx : 1; // REX.X
- uint_t rex_reg : 1; // REX.R
- uint_t rex_op_size : 1; // REX.W
-
+ uint_t rex_rm : 1; // REX.B
+ uint_t rex_sib_idx : 1; // REX.X
+ uint_t rex_reg : 1; // REX.R
+ uint_t rex_op_size : 1; // REX.W
+ } __attribute__((packed));
+ } __attribute__((packed));
} __attribute__((packed));
#include <palacios/vmm_types.h>
-
/* .... Giant fucking switch tables */
SMSW,
CLTS,
INVLPG,
+ INT, // KCH: adding software interrupts
MOV_CR2,
MOV_2CR,
case LONG:
if (instr->prefixes.rex_op_size) {
return 8;
+ } else {
+ return 4;
}
case PROTECTED:
case PROTECTED_PAE:
return -1;
}
+ case INT: // KCH
case MOV_DR2:
case MOV_2DR:
case MOV_CR2:
return -1;
}
+
return 0;
}
struct v3_ctrl_regs * crs = &(core->ctrl_regs);
- PrintDebug("\t Ctrl regs %d\n", reg_code);
+ // PrintDebug("\t Ctrl regs %d\n", reg_code);
switch (reg_code) {
case 0:
case 0xf4:
return HLT;
-
+
+ // KCH
+ case 0xcd:
+ return INT;
case 0xf6: {
struct modrm_byte * modrm = (struct modrm_byte *)&(instr[1]);
case SETO: return "SETO";
case STOS_8: return "STOS_8";
case STOS: return "STOS";
+ case INT: return "INT"; // KCH
case INVALID_INSTR:
default:
help
Provides the inspection extension
++config SW_INTERRUPTS
++ bool "Enable interception and hooking of software interrupts"
++ default n
++ help
++ This feature will cause the VMM to intercept the execution
++ of software interrupts (i.e. the INTn instruction) and enable
++ any INT vector to be hooked
++
++config SWINTR_PASSTHROUGH
++ bool "Hook all unhandled sofware interrupts for passthrough"
++ depends on SW_INTERRUPTS
++ default n
++ help
++ If enabled, this will cause all software interrupts
++ (INT instruction vectors) to be hooked for passthrough.
++ May reduce performance but useful for debugging.
++
++config SYSCALL_HIJACK
++ bool "Enable System Call Hijacking"
++ depends on SW_INTERRUPTS
++ default n
++ help
++ Enable the VMM to hijack system calls executed by the guest.
++ If enabled, the VMM will hook execution of INT 80
++ (support for Fast-System Calls coming soon)
++
++config SYSCALL_PASSTHROUGH
++ bool "Hook all unhandled system calls for passthrough"
++ depends on SYSCALL_HIJACK
++ default n
++ help
++ If enabled, this option will cause all system calls
++ that are not explicitly hooked to be hooked for
++ passthrough. This is useful for debugging.
++
++config HIJACK_SYSCALL_MSR
++ bool "Intercept Syscall-related MSR reads & writes"
++ depends on SYSCALL_HIJACK
++ default n
++ help
++ Allow the VMM to intercept reads and writes to MSRs
++ related to SYSCALL and SYSENTER instructions. Specifically,
++ it will intercept R/W to STAR, CSTAR, and LSTAR.
++
endmenu
obj-y += null.o
- obj-$(CONFIG_EXT_MTRRS) += ext_mtrr.o
- obj-$(CONFIG_EXT_VTSC) += ext_vtsc.o
- obj-$(CONFIG_EXT_VTIME) += ext_vtime.o
- obj-$(CONFIG_EXT_INSPECTOR) += ext_inspector.o
+ obj-$(V3_CONFIG_EXT_MTRRS) += ext_mtrr.o
+ obj-$(V3_CONFIG_EXT_VTSC) += ext_vtsc.o
+ obj-$(V3_CONFIG_EXT_VTIME) += ext_vtime.o
+ obj-$(V3_CONFIG_EXT_INSPECTOR) += ext_inspector.o
++
++obj-$(V3_CONFIG_SYSCALL_HIJACK) += vmm_syscall_hijack.o
++obj-$(V3_CONFIG_SYSCALL_HIJACK) += vmm_linux_syscall_map.o
++obj-$(V3_CONFIG_SYSCALL_HIJACK) += vmm_mpi_accel.o
++obj-$(V3_CONFIG_SYSCALL_HIJACK) += vmm_process_environment.o
++obj-$(V3_CONFIG_SYSCALL_HIJACK) += vmm_execve_hook.o
vmm_cpuid.o \
vmm_xml.o \
vmm_mem_hook.o \
- vmm_mptable.o \
vmm_extensions.o \
vmm_mtrr.o \
vmm_multitree.o \
- obj-$(CONFIG_XED) += vmm_xed.o
- obj-$(CONFIG_V3_DECODER) += vmm_v3dec.o
+ obj-$(V3_CONFIG_XED) += vmm_xed.o
+ obj-$(V3_CONFIG_V3_DECODER) += vmm_v3dec.o
- obj-$(CONFIG_SVM) += svm.o \
- svm_io.o \
- svm_lowlevel.o \
- svm_msr.o \
- svm_pause.o \
- svm_wbinvd.o \
- svm_handler.o \
- vmcb.o
+ obj-$(V3_CONFIG_SVM) += svm.o \
+ svm_io.o \
+ svm_lowlevel.o \
+ svm_msr.o \
+ svm_pause.o \
+ svm_wbinvd.o \
+ svm_handler.o \
+ vmcb.o
- obj-$(CONFIG_VMX) += vmx.o \
- vmx_handler.o \
- vmx_io.o \
- vmx_lowlevel.o \
- vmx_msr.o \
- vmx_hw_info.o \
- vmcs.o \
- vmx_ctrl_regs.o \
- vmx_assist.o
+ obj-$(V3_CONFIG_VMX) += vmx.o \
+ vmx_handler.o \
+ vmx_io.o \
+ vmx_lowlevel.o \
+ vmx_msr.o \
+ vmx_hw_info.o \
+ vmcs.o \
+ vmx_ctrl_regs.o \
+ vmx_assist.o \
+ vmx_ept.o
- obj-$(CONFIG_INSTRUMENT_VMM) += vmm_instrument.o
- obj-$(CONFIG_TELEMETRY) += vmm_telemetry.o
+ obj-$(V3_CONFIG_TELEMETRY) += vmm_telemetry.o
- obj-$(CONFIG_VNET) += vmm_vnet_core.o
-
-
- obj-$(CONFIG_SYMBIOTIC) += vmm_symbiotic.o vmm_symspy.o
- obj-$(CONFIG_SYMCALL) += vmm_symcall.o
- obj-$(CONFIG_SYMMOD) += vmm_symmod.o
-
- obj-$(CONFIG_SYSCALL_HIJACK) += vmm_syscall_hijack.o
- obj-$(CONFIG_SYSCALL_HIJACK) += vmm_linux_syscall_map.o
- obj-$(CONFIG_SYSCALL_HIJACK) += vmm_mpi_accel.o
- obj-$(CONFIG_SYSCALL_HIJACK) += vmm_process_environment.o
- obj-$(CONFIG_SYSCALL_HIJACK) += vmm_execve_hook.o
+ obj-$(V3_CONFIG_SYMBIOTIC) += vmm_symbiotic.o vmm_symspy.o
+ obj-$(V3_CONFIG_SYMCALL) += vmm_symcall.o
+ obj-$(V3_CONFIG_SYMMOD) += vmm_symmod.o
-
obj-y += mmu/
+
/*
* This file is part of the Palacios Virtual Machine Monitor developed
* by the V3VEE Project with funding from the United States National
#include <palacios/vmm_sprintf.h>
- #ifndef CONFIG_DEBUG_SVM
+ #ifndef V3_CONFIG_DEBUG_SVM
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
uint32_t v3_last_exit;
// This is a global pointer to the host's VMCB
- static addr_t host_vmcbs[CONFIG_MAX_CPUS] = { [0 ... CONFIG_MAX_CPUS - 1] = 0};
+ static addr_t host_vmcbs[V3_CONFIG_MAX_CPUS] = { [0 ... V3_CONFIG_MAX_CPUS - 1] = 0};
ctrl_area->instrs.HLT = 1;
- #ifdef CONFIG_TIME_VIRTUALIZE_TSC
+ #ifdef V3_CONFIG_TIME_VIRTUALIZE_TSC
ctrl_area->instrs.RDTSC = 1;
ctrl_area->svm_instrs.RDTSCP = 1;
#endif
ctrl_area->instrs.PAUSE = 1;
ctrl_area->instrs.shutdown_evts = 1;
+ /* KCH: intercept SW Interrupts (INT instr) */
- #ifdef CONFIG_SW_INTERRUPTS
++#ifdef V3_CONFIG_SW_INTERRUPTS
+ ctrl_area->instrs.INTn = 1;
+#endif
+
/* DEBUG FOR RETURN CODE */
ctrl_area->exit_code = 1;
&v3_handle_efer_write,
core);
- #ifdef CONFIG_HIJACK_MSR
- /* KCH: for SYSCALL and SYSENTER interception */
++#ifdef V3_CONFIG_HIJACK_SYSCALL_MSR
++ /* KCH: we're not hooking these to TRAP them,
++ instead, we're going to catch the target EIP.
++ Hopefully this EIP is the entry point in the ELF located in the
++ vsyscall page. We can inject checks into the code segment such that
++ we don't have to exit on uninteresting system calls. This should
++ give us much better performance than INT 80, and should even obviate
++ the need to deal with software interrupts at all */
+ v3_hook_msr(core->vm_info, STAR_MSR,
+ &v3_handle_star_read,
+ &v3_handle_star_write,
+ core);
+ v3_hook_msr(core->vm_info, LSTAR_MSR,
+ &v3_handle_lstar_read,
+ &v3_handle_lstar_write,
+ core);
+ v3_hook_msr(core->vm_info, CSTAR_MSR,
+ &v3_handle_cstar_read,
+ &v3_handle_cstar_write,
+ core);
++
++ /* KCH: this probably isn't necessary, as
++ SYSENTER is only used in legacy mode. In fact,
++ in long mode it results in an illegal instruction
++ exception */
++ v3_hook_msr(core->vm_info, IA32_SYSENTER_EIP_MSR,
++ &v3_handle_seeip_read,
++ &v3_handle_seeip_write,
++ core);
+#endif
+
if (core->shdw_pg_mode == SHADOW_PAGING) {
PrintDebug("Creating initial shadow page table\n");
if ((info->intr_core_state.irq_pending == 1) && (guest_ctrl->guest_ctrl.V_IRQ == 0)) {
- #ifdef CONFIG_DEBUG_INTERRUPTS
+ #ifdef V3_CONFIG_DEBUG_INTERRUPTS
PrintDebug("INTAK cycle completed for irq %d\n", info->intr_core_state.irq_vector);
#endif
}
if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 0)) {
- #ifdef CONFIG_DEBUG_INTERRUPTS
+ #ifdef V3_CONFIG_DEBUG_INTERRUPTS
PrintDebug("Interrupt %d taken by guest\n", info->intr_core_state.irq_vector);
#endif
info->intr_core_state.irq_started = 0;
} else if ((info->intr_core_state.irq_started == 1) && (guest_ctrl->exit_int_info.valid == 1)) {
- #ifdef CONFIG_DEBUG_INTERRUPTS
+ #ifdef V3_CONFIG_DEBUG_INTERRUPTS
PrintDebug("EXIT INT INFO is set (vec=%d)\n", guest_ctrl->exit_int_info.vector);
#endif
}
if (info->excp_state.excp_error_code_valid) {
guest_ctrl->EVENTINJ.error_code = info->excp_state.excp_error_code;
guest_ctrl->EVENTINJ.ev = 1;
- #ifdef CONFIG_DEBUG_INTERRUPTS
+ #ifdef V3_CONFIG_DEBUG_INTERRUPTS
PrintDebug("Injecting exception %d with error code %x\n", excp, guest_ctrl->EVENTINJ.error_code);
#endif
}
guest_ctrl->EVENTINJ.valid = 1;
- #ifdef CONFIG_DEBUG_INTERRUPTS
+ #ifdef V3_CONFIG_DEBUG_INTERRUPTS
PrintDebug("<%d> Injecting Exception %d (CR2=%p) (EIP=%p)\n",
(int)info->num_exits,
guest_ctrl->EVENTINJ.vector,
v3_injecting_excp(info, excp);
} else if (info->intr_core_state.irq_started == 1) {
- #ifdef CONFIG_DEBUG_INTERRUPTS
+ #ifdef V3_CONFIG_DEBUG_INTERRUPTS
PrintDebug("IRQ pending from previous injection\n");
#endif
guest_ctrl->guest_ctrl.V_IRQ = 1;
guest_ctrl->guest_ctrl.V_IGN_TPR = 1;
guest_ctrl->guest_ctrl.V_INTR_PRIO = 0xf;
- #ifdef CONFIG_DEBUG_INTERRUPTS
+ #ifdef V3_CONFIG_DEBUG_INTERRUPTS
PrintDebug("Injecting Interrupt %d (EIP=%p)\n",
guest_ctrl->guest_ctrl.V_INTR_VECTOR,
(void *)(addr_t)info->rip);
case V3_NMI:
guest_ctrl->EVENTINJ.type = SVM_INJECTION_NMI;
break;
- case V3_SOFTWARE_INTR:
- guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
- break;
+ case V3_SOFTWARE_INTR: {
+#ifdef CONFIG_DEBUG_INTERRUPTS
+ PrintDebug("Caught an injected software interrupt\n");
+ PrintDebug("\ttype: %d, vector: %d\n", SVM_INJECTION_SOFT_INTR, info->intr_core_state.swintr_vector);
+#endif
+ guest_ctrl->EVENTINJ.type = SVM_INJECTION_SOFT_INTR;
+ guest_ctrl->EVENTINJ.vector = info->intr_core_state.swintr_vector;
+ guest_ctrl->EVENTINJ.valid = 1;
+
+ /* reset the software interrupt state.
+ we can do this because we know only one
+ sw int can be posted at a time on a given
+ core, unlike irqs */
+ info->intr_core_state.swintr_posted = 0;
+ info->intr_core_state.swintr_vector = 0;
+ break;
+ }
case V3_VIRTUAL_IRQ:
guest_ctrl->EVENTINJ.type = SVM_INJECTION_IRQ;
break;
guest_state->rip = info->rip;
guest_state->rsp = info->vm_regs.rsp;
- #ifdef CONFIG_SYMCALL
+ #ifdef V3_CONFIG_SYMCALL
if (info->sym_core_state.symcall_state.sym_call_active == 0) {
update_irq_entry_state(info);
}
(void *)(addr_t)info->rip);
*/
- #ifdef CONFIG_SYMCALL
+ #ifdef V3_CONFIG_SYMCALL
if (info->sym_core_state.symcall_state.sym_call_active == 1) {
if (guest_ctrl->guest_ctrl.V_IRQ == 1) {
V3_Print("!!! Injecting Interrupt during Sym call !!!\n");
exit_info2 = guest_ctrl->exit_info2;
- #ifdef CONFIG_SYMCALL
+ #ifdef V3_CONFIG_SYMCALL
if (info->sym_core_state.symcall_state.sym_call_active == 0) {
update_irq_exit_state(info);
}
// vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
// vmcb_ctrl_t * guest_ctrl = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
- PrintDebug("Starting SVM core %u\n", info->cpu_id);
+ PrintDebug("Starting SVM core %u (on logical core %u)\n", info->vcpu_id, info->pcpu_id);
- if (info->cpu_id == 0) {
+ if (info->vcpu_id == 0) {
info->core_run_state = CORE_RUNNING;
info->vm_info->run_state = VM_RUNNING;
} else {
- PrintDebug("SVM core %u: Waiting for core initialization\n", info->cpu_id);
+ PrintDebug("SVM core %u (on %u): Waiting for core initialization\n", info->vcpu_id, info->pcpu_id);
while (info->core_run_state == CORE_STOPPED) {
v3_yield(info);
- //PrintDebug("SVM core %u: still waiting for INIT\n",info->cpu_id);
+ //PrintDebug("SVM core %u: still waiting for INIT\n", info->vcpu_id);
}
- PrintDebug("SVM core %u initialized\n", info->cpu_id);
+ PrintDebug("SVM core %u(on %u) initialized\n", info->vcpu_id, info->pcpu_id);
}
- PrintDebug("SVM core %u: I am starting at CS=0x%x (base=0x%p, limit=0x%x), RIP=0x%p\n",
- info->cpu_id, info->segments.cs.selector, (void *)(info->segments.cs.base),
+ PrintDebug("SVM core %u(on %u): I am starting at CS=0x%x (base=0x%p, limit=0x%x), RIP=0x%p\n",
+ info->vcpu_id, info->pcpu_id,
+ info->segments.cs.selector, (void *)(info->segments.cs.base),
info->segments.cs.limit, (void *)(info->rip));
- PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p)\n", info->cpu_id, (void *)info->vmm_data);
+ PrintDebug("SVM core %u: Launching SVM VM (vmcb=%p) (on cpu %u)\n",
+ info->vcpu_id, (void *)info->vmm_data, info->pcpu_id);
//PrintDebugVMCB((vmcb_t*)(info->vmm_data));
v3_start_time(info);
info->vm_info->run_state = VM_ERROR;
- V3_Print("SVM core %u: SVM ERROR!!\n", info->cpu_id);
+ V3_Print("SVM core %u: SVM ERROR!!\n", info->vcpu_id);
v3_print_guest_state(info);
- V3_Print("SVM core %u: SVM Exit Code: %p\n", info->cpu_id, (void *)(addr_t)guest_ctrl->exit_code);
+ V3_Print("SVM core %u: SVM Exit Code: %p\n", info->vcpu_id, (void *)(addr_t)guest_ctrl->exit_code);
- V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
- V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
+ V3_Print("SVM core %u: exit_info1 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info1));
+ V3_Print("SVM core %u: exit_info1 high = 0x%.8x\n", info->vcpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info1)) + 4));
- V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->cpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
- V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->cpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
+ V3_Print("SVM core %u: exit_info2 low = 0x%.8x\n", info->vcpu_id, *(uint_t*)&(guest_ctrl->exit_info2));
+ V3_Print("SVM core %u: exit_info2 high = 0x%.8x\n", info->vcpu_id, *(uint_t *)(((uchar_t *)&(guest_ctrl->exit_info2)) + 4));
linear_addr = get_addr_linear(info, info->rip, &(info->segments.cs));
v3_gva_to_hva(info, linear_addr, &host_addr);
}
- V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->cpu_id, (void *)host_addr);
+ V3_Print("SVM core %u: Host Address of rip = 0x%p\n", info->vcpu_id, (void *)host_addr);
- V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->cpu_id, (void *)host_addr);
+ V3_Print("SVM core %u: Instr (15 bytes) at %p:\n", info->vcpu_id, (void *)host_addr);
v3_dump_mem((uint8_t *)host_addr, 15);
v3_print_stack(info);
}
+
/*
- if ((info->num_exits % 5000) == 0) {
+ if ((info->num_exits % 50000) == 0) {
V3_Print("SVM Exit number %d\n", (uint32_t)info->num_exits);
+ v3_print_guest_state(info);
}
*/
+ int v3_reset_svm_vm_core(struct guest_info * core, addr_t rip) {
+ // init vmcb_bios
+
+ // Write the RIP, CS, and descriptor
+ // assume the rest is already good to go
+ //
+ // vector VV -> rip at 0
+ // CS = VV00
+ // This means we start executing at linear address VV000
+ //
+ // So the selector needs to be VV00
+ // and the base needs to be VV000
+ //
+ core->rip = 0;
+ core->segments.cs.selector = rip << 8;
+ core->segments.cs.limit = 0xffff;
+ core->segments.cs.base = rip << 12;
+
+ return 0;
+ }
+
+
+
+
+
/* Checks machine SVM capability */
/* Implemented from: AMD Arch Manual 3, sect 15.4 */
}
+
void v3_init_svm_cpu(int cpu_id) {
reg_ex_t msr;
extern v3_cpu_arch_t v3_cpu_types[];
#include <palacios/vmm_hypercall.h>
#include <palacios/vmm_cpuid.h>
#include <palacios/vmm_direct_paging.h>
+#include <palacios/vmm_syscall_hijack.h>
- #ifndef CONFIG_DEBUG_SVM
+ #ifndef V3_CONFIG_DEBUG_SVM
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
#include <palacios/vmm_telemetry.h>
#endif
int v3_handle_svm_exit(struct guest_info * info, addr_t exit_code, addr_t exit_info1, addr_t exit_info2) {
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
if (info->vm_info->enable_telemetry) {
v3_telemetry_start_exit(info);
}
break;
case VMEXIT_CR0_WRITE:
- #ifdef CONFIG_DEBUG_CTRL_REGS
+ #ifdef V3_CONFIG_DEBUG_CTRL_REGS
PrintDebug("CR0 Write\n");
#endif
if (v3_handle_cr0_write(info) == -1) {
}
break;
case VMEXIT_CR0_READ:
- #ifdef CONFIG_DEBUG_CTRL_REGS
+ #ifdef V3_CONFIG_DEBUG_CTRL_REGS
PrintDebug("CR0 Read\n");
#endif
if (v3_handle_cr0_read(info) == -1) {
}
break;
case VMEXIT_CR3_WRITE:
- #ifdef CONFIG_DEBUG_CTRL_REGS
+ #ifdef V3_CONFIG_DEBUG_CTRL_REGS
PrintDebug("CR3 Write\n");
#endif
if (v3_handle_cr3_write(info) == -1) {
break;
case VMEXIT_CR3_READ:
- #ifdef CONFIG_DEBUG_CTRL_REGS
+ #ifdef V3_CONFIG_DEBUG_CTRL_REGS
PrintDebug("CR3 Read\n");
#endif
if (v3_handle_cr3_read(info) == -1) {
}
break;
case VMEXIT_CR4_WRITE:
- #ifdef CONFIG_DEBUG_CTRL_REGS
+ #ifdef V3_CONFIG_DEBUG_CTRL_REGS
PrintDebug("CR4 Write\n");
#endif
if (v3_handle_cr4_write(info) == -1) {
}
break;
case VMEXIT_CR4_READ:
- #ifdef CONFIG_DEBUG_CTRL_REGS
+ #ifdef V3_CONFIG_DEBUG_CTRL_REGS
PrintDebug("CR4 Read\n");
#endif
if (v3_handle_cr4_read(info) == -1) {
case VMEXIT_EXCP14: {
addr_t fault_addr = exit_info2;
pf_error_t * error_code = (pf_error_t *)&(exit_info1);
- #ifdef CONFIG_DEBUG_SHADOW_PAGING
+ #ifdef V3_CONFIG_DEBUG_SHADOW_PAGING
PrintDebug("PageFault at %p (error=%d)\n",
(void *)fault_addr, *(uint_t *)error_code);
#endif
}
break;
}
+ case VMEXIT_SWINT:
+#ifdef CONFIG_DEBUG_INTERRUPTS
+ PrintDebug("Intercepted SW Interrupt\n");
+#endif
+ if (v3_handle_swintr(info) == -1) {
+ PrintError("Error handling software interrupt\n");
+ return -1;
+ }
+ break;
case VMEXIT_INVLPG:
if (info->shdw_pg_mode == SHADOW_PAGING) {
- #ifdef CONFIG_DEBUG_SHADOW_PAGING
+ #ifdef V3_CONFIG_DEBUG_SHADOW_PAGING
PrintDebug("Invlpg\n");
#endif
if (v3_handle_shadow_invlpg(info) == -1) {
return -1;
}
- break;
+ break;
+ case VMEXIT_NMI:
+ // handled by interrupt dispatcher
+ break;
case VMEXIT_INTR:
// handled by interrupt dispatch earlier
break;
// handle_svm_smi(info); // ignored for now
break;
case VMEXIT_HLT:
- #ifdef CONFIG_DEBUG_HALT
+ #ifdef V3_CONFIG_DEBUG_HALT
PrintDebug("Guest halted\n");
#endif
if (v3_handle_halt(info) == -1) {
}
break;
case VMEXIT_WBINVD:
- #ifdef CONFIG_DEBUG_EMULATOR
+ #ifdef V3_CONFIG_DEBUG_EMULATOR
PrintDebug("WBINVD\n");
#endif
if (v3_handle_svm_wbinvd(info) == -1) {
}
break;
case VMEXIT_RDTSC:
- #ifdef CONFIG_DEBUG_TIME
+ #ifdef V3_CONFIG_DEBUG_TIME
PrintDebug("RDTSC/RDTSCP\n");
#endif
if (v3_handle_rdtsc(info) == -1) {
}
break;
case VMEXIT_RDTSCP:
- #ifdef CONFIG_DEBUG_TIME
+ #ifdef V3_CONFIG_DEBUG_TIME
PrintDebug("RDTSCP\n");
#endif
if (v3_handle_rdtscp(info) == -1) {
}
// END OF SWITCH (EXIT_CODE)
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
if (info->vm_info->enable_telemetry) {
v3_telemetry_end_exit(info, exit_code);
}
#include <palacios/vmm_xed.h>
#include <palacios/vmm_direct_paging.h>
- #ifdef CONFIG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_SYSCALL_HIJACK
+#include <palacios/vmm_syscall_hijack.h>
+#include <palacios/vmm_mpi_accel.h>
+#endif
+
v3_cpu_mode_t v3_get_vm_cpu_mode(struct guest_info * info) {
v3_print_guest_state(core);
// init SVM/VMX
- #ifdef CONFIG_SVM
+ #ifdef V3_CONFIG_SVM
if ((cpu_type == V3_SVM_CPU) || (cpu_type == V3_SVM_REV3_CPU)) {
cpu_valid = 1;
PrintDebugVMCB((vmcb_t *)(core->vmm_data));
}
#endif
- #ifdef CONFIG_VMX
- if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
+ #ifdef V3_CONFIG_VMX
+ if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU) || (cpu_type == V3_VMX_EPT_UG_CPU)) {
cpu_valid = 1;
v3_print_vmcs();
}
}
- #ifdef CONFIG_SVM
+ #ifdef V3_CONFIG_SVM
#include <palacios/svm.h>
#include <palacios/svm_io.h>
#include <palacios/svm_msr.h>
#endif
- #ifdef CONFIG_VMX
+ #ifdef V3_CONFIG_VMX
#include <palacios/vmx.h>
#include <palacios/vmx_io.h>
#include <palacios/vmx_msr.h>
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
v3_init_telemetry(vm);
#endif
v3_init_time_vm(vm);
- #ifdef CONFIG_SYMBIOTIC
+ #ifdef V3_CONFIG_SYMBIOTIC
v3_init_symbiotic_vm(vm);
#endif
// init SVM/VMX
switch (cpu_type) {
- #ifdef CONFIG_SVM
+ #ifdef V3_CONFIG_SVM
case V3_SVM_CPU:
case V3_SVM_REV3_CPU:
v3_init_svm_io_map(vm);
v3_init_svm_msr_map(vm);
break;
#endif
- #ifdef CONFIG_VMX
+ #ifdef V3_CONFIG_VMX
case V3_VMX_CPU:
case V3_VMX_EPT_CPU:
+ case V3_VMX_EPT_UG_CPU:
v3_init_vmx_io_map(vm);
v3_init_vmx_msr_map(vm);
break;
- #ifdef CONFIG_SYMBIOTIC
+ #ifdef V3_CONFIG_SYMBIOTIC
v3_deinit_symbiotic_vm(vm);
#endif
// init SVM/VMX
switch (cpu_type) {
- #ifdef CONFIG_SVM
+ #ifdef V3_CONFIG_SVM
case V3_SVM_CPU:
case V3_SVM_REV3_CPU:
v3_deinit_svm_io_map(vm);
v3_deinit_svm_msr_map(vm);
break;
#endif
- #ifdef CONFIG_VMX
+ #ifdef V3_CONFIG_VMX
case V3_VMX_CPU:
case V3_VMX_EPT_CPU:
+ case V3_VMX_EPT_UG_CPU:
v3_deinit_vmx_io_map(vm);
v3_deinit_vmx_msr_map(vm);
break;
v3_deinit_io_map(vm);
v3_deinit_hypercall_map(vm);
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
v3_deinit_telemetry(vm);
#endif
/*
* Initialize the subsystem data strutures
*/
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
v3_init_core_telemetry(core);
#endif
v3_init_decoder(core);
- #ifdef CONFIG_SYMBIOTIC
+ #ifdef V3_CONFIG_SYMBIOTIC
v3_init_symbiotic_core(core);
#endif
+// KCH
- #ifdef CONFIG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_SYSCALL_HIJACK
+ v3_init_exec_hooks(core);
+ v3_init_mpi_accel(core);
- //v3_hook_swintr(core, 0x80, v3_syscall_handler, NULL);
- /* hook a poll syscall */
- //v3_hook_syscall(core, 5, v3_sysopen_handler, NULL);
- //v3_hook_syscall(core, 21, v3_sysmount_handler, NULL);
- //char * args[2];
- //args[0] = "./envtest";
- //args[1] = "LD_PRELOAD=./libcwrap.so";
- //v3_hook_syscall(core, 11, v3_sysexecve_handler, (void*)args);
+#endif
+
// init SVM/VMX
switch (cpu_type) {
- #ifdef CONFIG_SVM
+ #ifdef V3_CONFIG_SVM
case V3_SVM_CPU:
case V3_SVM_REV3_CPU:
if (v3_init_svm_vmcb(core, vm->vm_class) == -1) {
}
break;
#endif
- #ifdef CONFIG_VMX
+ #ifdef V3_CONFIG_VMX
case V3_VMX_CPU:
case V3_VMX_EPT_CPU:
+ case V3_VMX_EPT_UG_CPU:
if (v3_init_vmx_vmcs(core, vm->vm_class) == -1) {
PrintError("Error in VMX initialization\n");
return -1;
v3_cpu_arch_t cpu_type = v3_get_cpu_type(V3_Get_CPU());
- #ifdef CONFIG_SYMBIOTIC
+ #ifdef V3_CONFIG_SYMBIOTIC
v3_deinit_symbiotic_core(core);
#endif
v3_free_passthrough_pts(core);
- #ifdef CONFIG_TELEMETRY
+ #ifdef V3_CONFIG_TELEMETRY
v3_deinit_core_telemetry(core);
#endif
switch (cpu_type) {
- #ifdef CONFIG_SVM
+ #ifdef V3_CONFIG_SVM
case V3_SVM_CPU:
case V3_SVM_REV3_CPU:
if (v3_deinit_svm_vmcb(core) == -1) {
}
break;
#endif
- #ifdef CONFIG_VMX
+ #ifdef V3_CONFIG_VMX
case V3_VMX_CPU:
case V3_VMX_EPT_CPU:
+ case V3_VMX_EPT_UG_CPU:
if (v3_deinit_vmx_vmcs(core) == -1) {
PrintError("Error in VMX initialization\n");
return -1;
}
int v3_gpa_to_hpa(struct guest_info * info, addr_t gpa, addr_t * hpa) {
- struct v3_mem_region * reg = v3_get_mem_region(info->vm_info, info->cpu_id, gpa);
+ struct v3_mem_region * reg = v3_get_mem_region(info->vm_info, info->vcpu_id, gpa);
if (reg == NULL) {
PrintError("In GPA->HPA: Could not find address in shadow map (addr=%p) (NULL REGION)\n",
switch (guest_info->cpu_mode) {
case PROTECTED:
if (v3_translate_guest_pt_32(guest_info, guest_cr3, gva, gpa) == -1) {
- PrintDebug("Could not translate addr (%p) through 32 bit guest PT at %p\n",
- (void *)gva, (void *)(addr_t)guest_cr3);
+ /*PrintDebug("Could not translate addr (%p) through 32 bit guest PT at %p\n",
+ (void *)gva, (void *)(addr_t)guest_cr3);*/
return -1;
}
break;
case PROTECTED_PAE:
if (v3_translate_guest_pt_32pae(guest_info, guest_cr3, gva, gpa) == -1) {
- PrintDebug("Could not translate addr (%p) through 32 bitpae guest PT at %p\n",
- (void *)gva, (void *)(addr_t)guest_cr3);
+ /*PrintDebug("Could not translate addr (%p) through 32 bitpae guest PT at %p\n",
+ (void *)gva, (void *)(addr_t)guest_cr3);*/
return -1;
}
break;
case LONG_32_COMPAT:
case LONG_16_COMPAT:
if (v3_translate_guest_pt_64(guest_info, guest_cr3, gva, gpa) == -1) {
- PrintDebug("Could not translate addr (%p) through 64 bit guest PT at %p\n",
- (void *)gva, (void *)(addr_t)guest_cr3);
+ /*PrintDebug("Could not translate addr (%p) through 64 bit guest PT at %p\n",
+ (void *)gva, (void *)(addr_t)guest_cr3);*/
return -1;
}
break;
*hva = 0;
if (v3_gva_to_gpa(guest_info, gva, &gpa) != 0) {
- PrintError("In GVA->HVA: Invalid GVA(%p)->GPA lookup\n",
- (void *)gva);
+ /*PrintError("In GVA->HVA: Invalid GVA(%p)->GPA lookup\n",
+ (void *)gva);*/
return -1;
}
+/* KCH: currently only checks if we can perform a user-mode write
+ return 1 on success */
+int v3_gva_can_access(struct guest_info * core, addr_t gva) {
+
+ v3_reg_t guest_cr3 = 0;
+ pf_error_t access_type;
+ pt_access_status_t access_status;
+
+ access_type.write = 1;
+ access_type.user = 1;
+
+ if (core->mem_mode == PHYSICAL_MEM) {
+ return -1;
+ }
+
+ if (core->shdw_pg_mode == SHADOW_PAGING) {
+ guest_cr3 = core->shdw_pg_state.guest_cr3;
+ } else {
+ guest_cr3 = core->ctrl_regs.cr3;
+ }
+
+ // guest is in paged mode
+ switch (core->cpu_mode) {
+ case PROTECTED:
+ if (v3_check_guest_pt_32(core, guest_cr3, gva, access_type, &access_status) == -1) {
+ return -1;
+ }
+ break;
+ case PROTECTED_PAE:
+ if (v3_check_guest_pt_32pae(core, guest_cr3, gva, access_type, &access_status) == -1) {
+ return -1;
+ }
+ break;
+ case LONG:
+ case LONG_32_COMPAT:
+ case LONG_16_COMPAT:
+ if (v3_check_guest_pt_64(core, guest_cr3, gva, access_type, &access_status) == -1) {
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ if (access_status != PT_ACCESS_OK) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
#include <palacios/vmm_direct_paging.h>
#include <palacios/svm.h>
- #ifndef CONFIG_DEBUG_CTRL_REGS
+ #ifndef V3_CONFIG_DEBUG_CTRL_REGS
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
return 0;
}
+
+/* KCH: all of the star handlers are for syscall interposition */
+int v3_handle_star_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
+
+#ifdef CONFIG_DEBUG_SYSCALL_HIJACK
+ PrintDebug("STAR Read\n");
+#endif
+
+ return 0;
+}
+
+
+int v3_handle_star_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
+
- #ifdef CONFIG_DEBUG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_DEBUG_SYSCALL_HIJACK
+ PrintDebug("STAR Write\n");
+#endif
+ return 0;
+}
+
+
+int v3_handle_lstar_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
+
- #ifdef CONFIG_DEBUG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_DEBUG_SYSCALL_HIJACK
+ PrintDebug("LSTAR Read\n");
+#endif
+ return 0;
+}
+
+
+int v3_handle_lstar_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
+
- #ifdef CONFIG_DEBUG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_DEBUG_SYSCALL_HIJACK
++ ulong_t entry = ((ulong_t)src.hi << 32) | (ulong_t)src.lo;
+ PrintDebug("LSTAR Write\n");
++ PrintDebug("\tKernel syscall entry point: 0x%lx\n", entry);
+#endif
++
+ return 0;
+}
+
+
+int v3_handle_cstar_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
+
- #ifdef CONFIG_DEBUG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_DEBUG_SYSCALL_HIJACK
+ PrintDebug("CSTAR Read\n");
+#endif
+ return 0;
+}
+
+
+int v3_handle_cstar_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
+
- #ifdef CONFIG_DEBUG_SYSCALL_HIJACK
++#ifdef V3_CONFIG_DEBUG_SYSCALL_HIJACK
+ PrintDebug("CSTAR Write\n");
+#endif
++ return 0;
++}
++
++int v3_handle_seeip_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
++ /* we don't care about reads */
++ return 0;
++}
++
++int v3_handle_seeip_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
++#ifdef V3_CONFIG_DEBUG_SYSALL_HIJACK
++ PrintDebug("SYSENTER_EIP Write\n");
++#endif
+ return 0;
+}
+
+
int v3_handle_vm_cr_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
/* tell the guest that the BIOS disabled SVM, that way it doesn't get
* confused by the fact that CPUID reports SVM as available but it still
case V3_OP_STOS: return "V3_OP_STOS";
case V3_OP_MOVZX: return "V3_OP_MOVZX";
case V3_OP_MOVSX: return "V3_OP_MOVSX";
+ case V3_OP_INT: return "V3_OP_INT"; // KCH
case V3_INVALID_OP:
default:
return "V3_INVALID_OP";
void v3_print_instr(struct x86_instr * instr) {
V3_Print("Instr: %s (Len: %d)\n", op_type_to_str(instr->op_type), instr->instr_length);
- V3_Print("Prefixes= %x\n", *(uint32_t *)&(instr->prefixes));
+ V3_Print("Prefixes= %x\n", instr->prefixes.val);
if (instr->is_str_op) {
V3_Print("String OP (len=%d)\n", (uint32_t)instr->str_op_length);
#include <palacios/vmm_ctrl_regs.h>
#include <palacios/vmm_lock.h>
+#include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_decoder.h>
- #ifndef CONFIG_DEBUG_INTERRUPTS
+ #ifndef V3_CONFIG_DEBUG_INTERRUPTS
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
-
struct intr_controller {
struct intr_ctrl_ops * ctrl_ops;
};
+
+
void v3_init_intr_controllers(struct guest_info * info) {
struct v3_intr_core_state * intr_state = &(info->intr_core_state);
}
}
+
void * v3_register_intr_controller(struct guest_info * info, struct intr_ctrl_ops * ops, void * priv_data) {
struct intr_controller * ctrlr = (struct intr_controller *)V3_Malloc(sizeof(struct intr_controller));
return (void *)ctrlr;
}
+
void v3_remove_intr_controller(struct guest_info * core, void * handle) {
struct v3_intr_core_state * intr_state = &(core->intr_core_state);
struct intr_controller * ctrlr = handle;
V3_Free(ctrlr);
}
+
void * v3_register_intr_router(struct v3_vm_info * vm, struct intr_router_ops * ops, void * priv_data) {
struct intr_router * router = (struct intr_router *)V3_Malloc(sizeof(struct intr_router));
return (void *)router;
}
+
void v3_remove_intr_router(struct v3_vm_info * vm, void * handle) {
struct intr_router * router = handle;
struct intr_router * tmp = NULL;
}
-
-static inline struct v3_irq_hook * get_irq_hook(struct v3_vm_info * vm, uint_t irq) {
- V3_ASSERT(irq <= 256);
+static inline struct v3_irq_hook * get_irq_hook(struct v3_vm_info * vm, uint8_t irq) {
return vm->intr_routers.hooks[irq];
}
}
-
static int passthrough_irq_handler(struct v3_vm_info * vm, struct v3_interrupt * intr, void * priv_data) {
PrintDebug("[passthrough_irq_handler] raise_irq=%d (guest=0x%p)\n",
intr->irq, (void *)vm);
return v3_raise_irq(vm, intr->irq);
}
+
int v3_hook_passthrough_irq(struct v3_vm_info * vm, uint_t irq) {
int rc = v3_hook_irq(vm, irq, passthrough_irq_handler, NULL);
}
-
-
-
int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr) {
PrintDebug("v3_deliver_irq: irq=%d state=0x%p, \n", intr->irq, (void *)intr);
}
-
-
-
int v3_raise_virq(struct guest_info * info, int irq) {
struct v3_intr_core_state * intr_state = &(info->intr_core_state);
int major = irq / 8;
return 0;
}
+
int v3_lower_virq(struct guest_info * info, int irq) {
struct v3_intr_core_state * intr_state = &(info->intr_core_state);
int major = irq / 8;
return 0;
}
+
int v3_raise_irq(struct v3_vm_info * vm, int irq) {
struct intr_router * router = NULL;
struct v3_intr_routers * routers = &(vm->intr_routers);
}
+int v3_signal_swintr(struct guest_info * core, int vector) {
+ struct v3_intr_core_state * intr_state = &(core->intr_core_state);
+
+ PrintDebug("Signaling software interrupt in vmm_intr.c\n");
+ PrintDebug("\tINT vector: %d\n", vector);
+
+ intr_state->swintr_posted = 1;
+ intr_state->swintr_vector = vector;
+ return 0;
+}
+
+
+int v3_handle_swintr(struct guest_info * core) {
+
+ int ret = 0;
+ void * instr_ptr = NULL;
+ struct x86_instr instr;
+
+ if (core->mem_mode == PHYSICAL_MEM) {
+ ret = v3_gpa_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
+ } else {
+ ret = v3_gva_to_hva(core, get_addr_linear(core, core->rip, &(core->segments.cs)), (addr_t *)&instr_ptr);
+ }
+
+ if (ret == -1) {
+ PrintError("V3 SWintr Handler: Could not translate Instruction Address (%p)\n", (void *)core->rip);
+ return -1;
+ }
+
+ if (v3_decode(core, (addr_t)instr_ptr, &instr) == -1) {
+ PrintError("V3 SWintr Handler: Decoding Error\n");
+ return -1;
+ }
+
+ uint8_t vector = instr.dst_operand.operand;
+
+ struct v3_swintr_hook * hook = core->intr_core_state.swintr_hooks[vector];
+ if (hook == NULL) {
- #ifdef CONFIG_SWINTR_PASSTHROUGH
++#ifdef V3_CONFIG_SWINTR_PASSTHROUGH
+ if (v3_hook_passthrough_swintr(core, vector) == -1) {
+ PrintDebug("V3 SWintr Handler: Error hooking passthrough swintr\n");
+ return -1;
+ }
+ hook = core->intr_core_state.swintr_hooks[vector];
+#else
+ core->rip += instr.instr_length;
+ return v3_signal_swintr(core, vector);
+#endif
+ }
+
+ ret = hook->handler(core, vector, NULL);
+ if (ret == -1) {
+ PrintDebug("V3 SWintr Handler: Error in swintr hook\n");
+ return -1;
+ }
+
- /* at some point we may need to prioritize swints
++ /* KCH: at some point we may need to prioritize swints
+ so that they finish in time for the next
- instruction */
++ instruction... */
+ core->rip += instr.instr_length;
+ return v3_signal_swintr(core, vector);
+}
+
+
+static inline struct v3_swintr_hook * get_swintr_hook(struct guest_info * core, uint8_t vector) {
+ return core->intr_core_state.swintr_hooks[vector];
+}
+
+
+int v3_hook_swintr(struct guest_info * core,
+ uint8_t vector,
+ int (*handler)(struct guest_info * core, uint8_t vector, void * priv_data),
+ void * priv_data)
+{
+
+ struct v3_swintr_hook * hook = (struct v3_swintr_hook *)V3_Malloc(sizeof(struct v3_swintr_hook));
+
+ if (hook == NULL) {
+ return -1;
+ }
+
+ if (get_swintr_hook(core, vector) != NULL) {
+ PrintError("SWINT %d already hooked\n", vector);
+ return -1;
+ }
+
+ hook->handler = handler;
+ hook->priv_data = priv_data;
+
+ core->intr_core_state.swintr_hooks[vector] = hook;
+
+ return 0;
+}
+
+
+static int passthrough_swintr_handler(struct guest_info * core, uint8_t vector, void * priv_data) {
+
+ PrintDebug("[passthrough_swint_handler] INT vector=%d (guest=0x%p)\n",
+ vector, (void *)core);
+
+ return 0;
+}
+
+
+int v3_hook_passthrough_swintr(struct guest_info * core, uint8_t vector) {
+
+ int rc = v3_hook_swintr(core, vector, passthrough_swintr_handler, NULL);
+
+ if (rc) {
+ PrintError("guest_swintr_injection: failed to hook swint 0x%x (guest=0x%p)\n", vector, (void *)core);
+ return -1;
+ } else {
+ PrintDebug("guest_swintr_injection: hooked swint 0x%x (guest=0x%p)\n", vector, (void *)core);
+ return 0;
+ }
+
+ /* shouldn't get here */
+ return 0;
+}
+
+
void v3_clear_pending_intr(struct guest_info * core) {
struct v3_intr_core_state * intr_state = &(core->intr_core_state);
intr_state->irq_pending = 0;
-
}
}
}
+ // KCH: added for SWintr injection
+ if (intr_state->swintr_posted == 1) {
+ ret = V3_SOFTWARE_INTR;
+ }
+
v3_unlock_irqrestore(intr_state->irq_lock, irq_state);
return ret;
}
}
- #ifdef CONFIG_DEBUG_INTERRUPTS
+ #ifdef V3_CONFIG_DEBUG_INTERRUPTS
if (type == V3_INVALID_INTR) {
PrintError("[get_intr_type] Invalid_Intr\n");
}
*/
-
-
-
int v3_injecting_intr(struct guest_info * info, uint_t intr_num, v3_intr_type_t type) {
struct v3_intr_core_state * intr_state = &(info->intr_core_state);
#include <palacios/vmm_decoder.h>
#include <palacios/vmm_instr_decoder.h>
- #ifndef CONFIG_DEBUG_DECODER
+ #ifndef V3_CONFIG_DEBUG_DECODER
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
int length = 0;
- V3_Print("Decoding Instruction at %p\n", (void *)instr_ptr);
+ PrintDebug("Decoding Instruction at %p\n", (void *)instr_ptr);
memset(instr, 0, sizeof(struct x86_instr));
form = op_code_to_form((uint8_t *)(instr_ptr + length), &length);
- V3_Print("\t decoded as (%s)\n", op_form_to_str(form));
+ PrintDebug("\t decoded as (%s)\n", op_form_to_str(form));
if (form == INVALID_INSTR) {
PrintError("Could not find instruction form (%x)\n", *(uint32_t *)(instr_ptr + length));
instr->instr_length += length;
+ #ifdef V3_CONFIG_DEBUG_DECODER
v3_print_instr(instr);
+ #endif
return 0;
}
}
case INVLPG: {
uint8_t reg_code = 0;
-
+
ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), ®_code);
-
+
if (ret == -1) {
PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
return -1;
}
-
+
instr_ptr += ret;
-
+
+ instr->num_operands = 1;
+ break;
+ }
+ case LMSW:
+ case SMSW: {
+ uint8_t reg_code = 0;
+
+ ret = decode_rm_operand(core, instr_ptr, form, instr, &(instr->dst_operand), ®_code);
+
+ if (ret == -1) {
+ PrintError("Error decoding operand for (%s)\n", op_form_to_str(form));
+ return -1;
+ }
+
+ instr_ptr += ret;
+
+ instr->dst_operand.read = 1;
+
instr->num_operands = 1;
break;
}
case CLTS: {
// no operands.
break;
-
}
default:
PrintError("Invalid Instruction form: %s\n", op_form_to_str(form));
case MOV_2CR:
return V3_OP_MOV2CR;
+ // KCH: for syscall interposition
+ case INT:
+ return V3_OP_INT;
+
case MOV_MEM2_8:
case MOV_MEM2:
return V3_OP_MOVZX;
-
case ADC_2MEM_8:
case ADC_2MEM:
case ADC_MEM2_8:
- #ifndef CONFIG_DEBUG_DECODER
+ #ifndef V3_CONFIG_DEBUG_DECODER
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
xed_iform_enum_t iform = xed_decoded_inst_get_iform_enum(&xed_instr);
- #ifdef CONFIG_DEBUG_DECODER
+ #ifdef V3_CONFIG_DEBUG_DECODER
xed_iclass_enum_t iclass = xed_decoded_inst_get_iclass(&xed_instr);
PrintDebug("iform=%s, iclass=%s\n", xed_iform_enum_t2str(iform), xed_iclass_enum_t2str(iclass));
case XED_OPERAND_IMM0:
+ {
+ v3_op->size = xed_decoded_inst_get_immediate_width(&xed_instr);
+
+ if (v3_op->size > 4) {
+ PrintError("Unhandled 64 bit immediates\n");
+ return -1;
+ }
+ v3_op->operand = xed_decoded_inst_get_unsigned_immediate(&xed_instr);
+
+ v3_op->type = IMM_OPERAND;
+
+ }
+ break;
case XED_OPERAND_AGEN:
case XED_OPERAND_PTR:
case XED_OPERAND_RELBR:
instr->third_operand.type = REG_OPERAND;
- PrintDebug("Operand 3 mode: %s\n", xed_operand_action_enum_t2str(xed_operand_rw(op)));
+ PrintDebug("Operand 2 mode: %s\n", xed_operand_action_enum_t2str(xed_operand_rw(op)));
if (xed_operand_read(op)) {
case XED_IFORM_INVLPG_MEMb:
return V3_OP_INVLPG;
+ // KCH
+ case XED_IFORM_INT_IMM:
+ return V3_OP_INT;
+
/* Data Instructions */