From: Andy Gocke Date: Mon, 31 Aug 2009 23:53:12 +0000 (-0500) Subject: VMX is working for a 32-bit Linux kernel. It should also work for a 64-bit kernel... X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=cfcceed5890430afedcc544bd7dbb69e29dfd65a VMX is working for a 32-bit Linux kernel. It should also work for a 64-bit kernel, but that has not been tested. --- diff --git a/bios/vmxassist/vmxassist.bin b/bios/vmxassist/vmxassist.bin index e93a308..1b66639 100644 Binary files a/bios/vmxassist/vmxassist.bin and b/bios/vmxassist/vmxassist.bin differ diff --git a/palacios/include/palacios/svm_msr.h b/palacios/include/palacios/svm_msr.h index 6972afd..defb6fa 100644 --- a/palacios/include/palacios/svm_msr.h +++ b/palacios/include/palacios/svm_msr.h @@ -27,12 +27,6 @@ int v3_init_svm_msr_map(struct guest_info * info); -int v3_handle_msr_write(struct guest_info * info); - -int v3_handle_msr_read(struct guest_info * info); - - - #endif // ! __V3VEE__ diff --git a/palacios/include/palacios/vm_guest.h b/palacios/include/palacios/vm_guest.h index abf1cd6..241ec8a 100644 --- a/palacios/include/palacios/vm_guest.h +++ b/palacios/include/palacios/vm_guest.h @@ -178,6 +178,7 @@ struct guest_info { uint64_t yield_cycle_period; uint64_t yield_start_cycle; + uint64_t num_exits; #ifdef CONFIG_TELEMETRY uint_t enable_telemetry; diff --git a/palacios/include/palacios/vmcs.h b/palacios/include/palacios/vmcs.h index bff2e21..79efe4e 100644 --- a/palacios/include/palacios/vmcs.h +++ b/palacios/include/palacios/vmcs.h @@ -27,43 +27,22 @@ #include - /* Pin Based VM Execution Controls */ - /* INTEL MANUAL: 20-10 vol 3B */ -#define EXT_INTR_EXIT 0x00000001 -#define NMI_EXIT 0x00000008 -#define VIRTUAL_NMIS 0x00000020 -/* Processor Based VM Execution Controls */ -/* INTEL MANUAL: 20-11 vol. 3B */ -#define INTR_WIN_EXIT 0x00000004 -#define USE_TSC_OFFSET 0x00000008 -#define HLT_EXIT 0x00000080 -#define INVLPG_EXIT 0x00000200 -#define MWAIT_EXIT 0x00000400 -#define RDPMC_EXIT 0x00000800 -#define RDTSC_EXIT 0x00001000 -#define CR3_LOAD_EXIT 0x00008000 -#define CR3_STORE_EXIT 0x00010000 -#define CR8_LOAD_EXIT 0x00080000 -#define CR8_STORE_EXIT 0x00100000 -#define USE_TPR_SHADOW 0x00200000 -#define NMI_WINDOW_EXIT 0x00400000 -#define MOVDR_EXIT 0x00800000 -#define UNCOND_IO_EXIT 0x01000000 -#define USE_IO_BITMAPS 0x02000000 -#define USE_MSR_BITMAPS 0x10000000 -#define MONITOR_EXIT 0x20000000 -#define PAUSE_EXIT 0x40000000 -#define ACTIVE_SEC_CTRLS 0x80000000 +#include + /* VM-Exit Controls */ /* INTEL MANUAL: 20-16 vol. 3B */ #define HOST_ADDR_SPACE_SIZE 0x00000200 #define ACK_IRQ_ON_EXIT 0x00008000 /* Control register exit masks */ -#define CR0_PE 0x00000001 -#define CR0_PG 0x80000000 #define CR4_VMXE 0x00002000 +int v3_load_vmcs_guest_state(struct guest_info * info); +int v3_update_vmcs_guest_state(struct guest_info * info); +int v3_update_vmcs_host_state(struct guest_info * info); +int v3_update_vmcs_ctrl_fields(struct guest_info * info); + + typedef enum { VMCS_GUEST_ES_SELECTOR = 0x00000800, VMCS_GUEST_CS_SELECTOR = 0x00000802, @@ -107,6 +86,8 @@ typedef enum { VMCS_LINK_PTR_HIGH = 0x00002801, VMCS_GUEST_DBG_CTL = 0x00002802, VMCS_GUEST_DBG_CTL_HIGH = 0x00002803, + VMCS_GUEST_EFER = 0x00002805, + VMCS_GUEST_EFER_HIGH = 0x00002807, VMCS_GUEST_PERF_GLOBAL_CTRL = 0x00002808, VMCS_GUEST_PERF_GLOBAL_CTRL_HIGH = 0x00002809, @@ -137,7 +118,7 @@ typedef enum { VMCS_IDT_VECTOR_INFO = 0x00004408, VMCS_IDT_VECTOR_ERR = 0x0000440A, VMCS_EXIT_INSTR_LEN = 0x0000440C, - VMCS_VMX_INSTR_INFO = 0x0000440E, + VMCS_EXIT_INSTR_INFO = 0x0000440E, /* 32 bit Guest state fields */ VMCS_GUEST_ES_LIMIT = 0x00004800, VMCS_GUEST_CS_LIMIT = 0x00004802, @@ -215,64 +196,45 @@ typedef enum { VMCS_HOST_RIP = 0x00006C16, } vmcs_field_t; -int v3_vmcs_get_field_len(vmcs_field_t field); -const char* v3_vmcs_field_to_str(vmcs_field_t field); -void v3_print_vmcs(); - - - -/* Exit Vector Info */ -struct VMExitIntInfo { - uint32_t nr : 8; // IRQ number, exception vector, NMI = 2 - uint32_t type : 3; // (0: ext. IRQ , 2: NMI , 3: hw exception , 6: sw exception - uint32_t errorCode : 1; // 1: error Code present - uint32_t iret : 1; // something to do with NMIs and IRETs (Intel 3B, sec. 23.2.2) - uint32_t rsvd : 18; // always 0 - uint32_t valid : 1; // always 1 if valid -} __attribute__((packed)); - - -/* End Exit Vector Info */ - struct vmx_exception_bitmap { union { uint32_t value; - struct { - uint_t de : 1; // (0) divide by zero - uint_t db : 1; // (1) Debug - uint_t nmi : 1; // (2) Non-maskable interrupt - uint_t bp : 1; // (3) Breakpoint - uint_t of : 1; // (4) Overflow - uint_t br : 1; // (5) Bound-Range - uint_t ud : 1; // (6) Invalid-Opcode - uint_t nm : 1; // (7) Device-not-available - uint_t df : 1; // (8) Double Fault - uint_t ex9 : 1; - uint_t ts : 1; // (10) Invalid TSS - uint_t np : 1; // (11) Segment-not-present - uint_t ss : 1; // (12) Stack - uint_t gp : 1; // (13) General Protection Fault - uint_t pf : 1; // (14) Page fault - uint_t ex15 : 1; - uint_t mf : 1; // (15) Floating point exception - uint_t ac : 1; // (16) Alignment-check - uint_t mc : 1; // (17) Machine Check - uint_t xf : 1; // (18) SIMD floating-point - uint_t ex20 : 1; - uint_t ex21 : 1; - uint_t ex22 : 1; - uint_t ex23 : 1; - uint_t ex24 : 1; - uint_t ex25 : 1; - uint_t ex26 : 1; - uint_t ex27 : 1; - uint_t ex28 : 1; - uint_t ex29 : 1; - uint_t sx : 1; // (30) Security Exception - uint_t ex31 : 1; - } __attribute__ ((packed)); + struct { + uint_t de : 1; // (0) divide by zero + uint_t db : 1; // (1) Debug + uint_t nmi : 1; // (2) Non-maskable interrupt + uint_t bp : 1; // (3) Breakpoint + uint_t of : 1; // (4) Overflow + uint_t br : 1; // (5) Bound-Range + uint_t ud : 1; // (6) Invalid-Opcode + uint_t nm : 1; // (7) Device-not-available + uint_t df : 1; // (8) Double Fault + uint_t ex9 : 1; + uint_t ts : 1; // (10) Invalid TSS + uint_t np : 1; // (11) Segment-not-present + uint_t ss : 1; // (12) Stack + uint_t gp : 1; // (13) General Protection Fault + uint_t pf : 1; // (14) Page fault + uint_t ex15 : 1; + uint_t mf : 1; // (15) Floating point exception + uint_t ac : 1; // (16) Alignment-check + uint_t mc : 1; // (17) Machine Check + uint_t xf : 1; // (18) SIMD floating-point + uint_t ex20 : 1; + uint_t ex21 : 1; + uint_t ex22 : 1; + uint_t ex23 : 1; + uint_t ex24 : 1; + uint_t ex25 : 1; + uint_t ex26 : 1; + uint_t ex27 : 1; + uint_t ex28 : 1; + uint_t ex29 : 1; + uint_t sx : 1; // (30) Security Exception + uint_t ex31 : 1; + } __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__((packed)); @@ -281,8 +243,6 @@ struct vmx_exception_bitmap { /* Segment Selector Access Rights (32 bits) */ /* INTEL Manual: 20-4 vol 3B */ - - struct vmcs_segment_access { union { uint32_t value; @@ -319,7 +279,12 @@ struct vmcs_data { } __attribute__((packed)); -//uint_t VMCSRead(uint_t tag, void * val); + +int v3_vmcs_get_field_len(vmcs_field_t field); + +const char * v3_vmcs_field_to_str(vmcs_field_t field); + +void v3_print_vmcs(); #endif // ! __V3VEE__ diff --git a/palacios/include/palacios/svm_halt.h b/palacios/include/palacios/vmm_halt.h similarity index 86% rename from palacios/include/palacios/svm_halt.h rename to palacios/include/palacios/vmm_halt.h index 1a29fc2..c0e9169 100644 --- a/palacios/include/palacios/svm_halt.h +++ b/palacios/include/palacios/vmm_halt.h @@ -12,22 +12,22 @@ * All rights reserved. * * Author: Peter Dinda + * Author: Andy Gocke * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ -#ifndef __SVM_HALT_H -#define __SVM_HALT_H +#ifndef __VMM_HALT_H +#define __VMM_HALT_H #ifdef __V3VEE__ #include -#include #include -int v3_handle_svm_halt(struct guest_info * info); +int v3_handle_halt(struct guest_info * info); #endif // ! __V3VEE__ diff --git a/palacios/include/palacios/vmm_lowlevel.h b/palacios/include/palacios/vmm_lowlevel.h index 109c6d2..71af105 100644 --- a/palacios/include/palacios/vmm_lowlevel.h +++ b/palacios/include/palacios/vmm_lowlevel.h @@ -28,12 +28,9 @@ static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_t * ecx, addr_t * edx) { __asm__ __volatile__ ( - "pushl %%ebx\n\t" "cpuid\n\t" - "movl %%ebx, %%esi\n\t" - "popl %%ebx\n\t" : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) - : "a" (target) + : "0" (target), "2" (*ecx) ); return; } @@ -42,12 +39,9 @@ static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_ static void __inline__ v3_cpuid(uint_t target, addr_t * eax, addr_t * ebx, addr_t * ecx, addr_t * edx) { __asm__ __volatile__ ( - "pushq %%rbx\n\t" "cpuid\n\t" - "movq %%rbx, %%rsi\n\t" - "popq %%rbx\n\t" - : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) - : "a" (target) + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + : "0" (target), "2" (*ecx) ); return; } diff --git a/palacios/include/palacios/vmm_msr.h b/palacios/include/palacios/vmm_msr.h index ef66a60..f7e3202 100644 --- a/palacios/include/palacios/vmm_msr.h +++ b/palacios/include/palacios/vmm_msr.h @@ -83,6 +83,10 @@ struct v3_msr_hook * v3_get_msr_hook(struct guest_info * info, uint_t msr); void v3_print_msr_map(struct guest_info * info); +int v3_handle_msr_write(struct guest_info * info); + +int v3_handle_msr_read(struct guest_info * info); + #endif // ! __V3VEE__ diff --git a/palacios/include/palacios/vmx.h b/palacios/include/palacios/vmx.h index eebd289..f009a24 100644 --- a/palacios/include/palacios/vmx.h +++ b/palacios/include/palacios/vmx.h @@ -21,8 +21,8 @@ */ -#ifndef __VMX_H -#define __VMX_H +#ifndef __VMX_H__ +#define __VMX_H__ #ifdef __V3VEE__ @@ -58,6 +58,116 @@ #define CPUID_1_ECX_VTXFLAG 0x00000020 +struct vmx_pin_ctrls { + union { + uint32_t value; + struct { + uint_t ext_int_exit : 1; + uint_t rsvd1 : 2; + uint_t nmi_exit : 1; + uint_t rsvd2 : 1; + uint_t virt_nmi : 1; + uint_t active_preempt_timer : 1; + uint_t rsvd3 : 25; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + + +struct vmx_pri_proc_ctrls { + union { + uint32_t value; + struct { + uint_t rsvd1 : 2; + uint_t int_wndw_exit : 1; + uint_t tsc_offset : 1; + uint_t rsvd2 : 3; + uint_t hlt_exit : 1; + uint_t rsvd3 : 1; + uint_t invlpg_exit : 1; + uint_t mwait_exit : 1; + uint_t rdpmc_exit : 1; + uint_t rdtsc_exit : 1; + uint_t rsvd4 : 2; + uint_t cr3_ld_exit : 1; + uint_t cr3_str_exit : 1; + uint_t rsvd5 : 2; + uint_t cr8_ld_exit : 1; + uint_t cr8_str_exit : 1; + uint_t tpr_shdw : 1; + uint_t nmi_wndw_exit : 1; + uint_t mov_dr_exit : 1; + uint_t uncon_io_exit : 1; + uint_t use_io_bitmap : 1; + uint_t rsvd6 : 1; + uint_t monitor_trap : 1; + uint_t use_msr_bitmap : 1; + uint_t monitor_exit : 1; + uint_t pause_exit : 1; + uint_t sec_ctrls : 1; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + +struct vmx_sec_proc_ctrls { + union { + uint32_t value; + struct { + uint_t virt_apic_acc : 1; + uint_t enable_ept : 1; + uint_t desc_table_exit : 1; + uint_t enable_rdtscp : 1; + uint_t virt_x2apic : 1; + uint_t enable_vpid : 1; + uint_t unrstrct_guest : 1; + uint_t rsvd1 : 2; + uint_t pause_loop_exit : 1; + uint_t rsvd2 : 21; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + +struct vmx_exit_ctrls { + union { + uint32_t value; + struct { + uint_t rsvd1 : 2; + uint_t save_dbg_ctrls : 1; + uint_t rsvd2 : 6; + uint_t host_64_on : 1; + uint_t rsvd3 : 2; + uint_t ld_perf_glbl_ctrl : 1; + uint_t rsvd4 : 2; + uint_t ack_int_on_exit : 1; + uint_t rsvd5 : 2; + uint_t save_pat : 1; + uint_t ld_pat : 1; + uint_t save_efer : 1; + uint_t ld_efer : 1; + uint_t save_preempt_timer : 1; + uint_t rsvd6 : 9; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + +struct vmx_entry_ctrls { + union { + uint32_t value; + struct { + uint_t rsvd1 : 2; + uint_t ld_dbg_ctrls : 1; + uint_t rsvd2 : 6; + uint_t guest_ia32e : 1; + uint_t smm_entry : 1; + uint_t no_dual_monitor : 1; + uint_t rsvd3 : 1; + uint_t ld_perf_glbl_ctrl : 1; + uint_t ld_pat : 1; + uint_t ld_efer : 1; + uint_t rsvd4 : 16; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); struct vmx_basic_msr { uint32_t revision; @@ -75,31 +185,26 @@ typedef enum { } vmx_state_t; struct tss_descriptor { - union { - ulong_t value; - struct { - uint16_t limit1; - uint16_t base1; - uint_t base2 : 8; - /* In IA32, type follows the form 10B1b, where B is the busy flag */ - uint_t type : 4; - uint_t zero1 : 1; - uint_t dpl : 2; - uint_t present : 1; - uint_t limit2 : 4; - uint_t available : 1; - uint_t zero2 : 1; - uint_t zero3 : 1; - uint_t granularity : 1; - uint_t base3 : 8; + uint16_t limit1; + uint16_t base1; + uint_t base2 : 8; + /* In IA32, type follows the form 10B1b, where B is the busy flag */ + uint_t type : 4; + uint_t zero1 : 1; + uint_t dpl : 2; + uint_t present : 1; + uint_t limit2 : 4; + uint_t available : 1; + uint_t zero2 : 1; + uint_t zero3 : 1; + uint_t granularity : 1; + uint_t base3 : 8; #ifdef __V3_64BIT__ - uint32_t base4; - uint_t rsvd1 : 8; - uint_t zero4 : 5; - uint_t rsvd2 : 19; + uint32_t base4; + uint_t rsvd1 : 8; + uint_t zero4 : 5; + uint_t rsvd2 : 19; #endif - } __attribute__((packed)); - } __attribute__((packed)); }__attribute__((packed)); struct vmcs_host_state { @@ -110,36 +215,22 @@ struct vmcs_host_state { struct vmx_data { vmx_state_t state; - addr_t vmcs_ptr_phys; struct vmcs_host_state host_state; - /* VMX Control Fields */ - uint32_t pinbased_ctrls; - uint32_t pri_procbased_ctrls; - uint32_t sec_procbased_ctrls; - uint32_t exit_ctrls; - uint32_t entry_ctrls; -}; + addr_t vmcs_ptr_phys; -enum InstructionType { VM_UNKNOWN_INST, VM_MOV_TO_CR0 } ; + uint8_t ia32e_avail; -struct Instruction { - enum InstructionType type; - uint_t address; - uint_t size; - uint_t input1; - uint_t input2; - uint_t output; + /* VMX Control Fields */ + struct vmx_pin_ctrls pin_ctrls; + struct vmx_pri_proc_ctrls pri_proc_ctrls; + struct vmx_sec_proc_ctrls sec_proc_ctrls; + struct vmx_exit_ctrls exit_ctrls; + struct vmx_entry_ctrls entry_ctrls; }; - - - int v3_is_vmx_capable(); -void v3_init_vmx(struct v3_ctrl_ops* vm_ops); -int v3_update_vmcs_guest_state(struct guest_info * info); -int v3_update_vmcs_ctrl_fields(struct guest_info * info); -int v3_update_vmcs_host_state(struct guest_info * info); +void v3_init_vmx(struct v3_ctrl_ops * vm_ops); diff --git a/palacios/include/palacios/vmx_ctrl_regs.h b/palacios/include/palacios/vmx_ctrl_regs.h index f35e878..88b24f4 100644 --- a/palacios/include/palacios/vmx_ctrl_regs.h +++ b/palacios/include/palacios/vmx_ctrl_regs.h @@ -2,4 +2,6 @@ #include #include -int v3_vmx_handle_cr0_write(struct guest_info * info, v3_reg_t new_val); +int v3_vmx_handle_cr0_access(struct guest_info * info); +int v3_vmx_handle_cr3_access(struct guest_info * info); + diff --git a/palacios/include/palacios/vmx_handler.h b/palacios/include/palacios/vmx_handler.h index 1507e4a..1152b5c 100644 --- a/palacios/include/palacios/vmx_handler.h +++ b/palacios/include/palacios/vmx_handler.h @@ -81,16 +81,64 @@ typedef enum { } vmx_exit_t; /* VMCS Exit QUALIFICATIONs */ -struct vmexit_io_qual { - uint32_t access_size : 3; // (0: 1 Byte ;; 1: 2 Bytes ;; 3: 4 Bytes) - uint32_t dir : 1; // (0: Out ;; 1: In) - uint32_t string : 1; // (0: not string ;; 1: string) - uint32_t rep : 1; // (0: not REP ;; 1: REP) - uint32_t op_enc : 1; // (0: DX ;; 1: immediate) - uint32_t rsvd : 9; // Set to 0 - uint32_t port : 16; // IO Port Number +struct vmx_exit_io_qual { + union { + uint32_t value; + struct { + uint32_t access_size : 3; // (0: 1 Byte ;; 1: 2 Bytes ;; 3: 4 Bytes) + uint32_t dir : 1; // (0: Out ;; 1: In) + uint32_t string : 1; // (0: not string ;; 1: string) + uint32_t rep : 1; // (0: not REP ;; 1: REP) + uint32_t op_enc : 1; // (0: DX ;; 1: immediate) + uint32_t rsvd : 9; // Set to 0 + uint32_t port : 16; // IO Port Number + } __attribute__((packed)); + } __attribute__((packed)); } __attribute__((packed)); +struct vmx_exit_io_instr_info { + union { + uint32_t value; + struct { + uint32_t undef1 : 7; + uint32_t addr_size : 3; + uint32_t undef2 : 5; + uint32_t seg_reg : 3; + uint32_t undef3 : 14; + } __attribute__((packed)); + } __attribute__((packed)); +} __attribute__((packed)); + +/* Exit Interrupt Vector Info */ +struct vmx_exit_int_info { + union { + uint32_t value; + struct { + uint32_t vector : 8; // IRQ number, exception vector, NMI = 2 + uint32_t type : 3; // (0: ext. IRQ , 2: NMI , 3: hw exception , 6: sw exception + uint32_t error_code : 1; // 1: error Code present + uint32_t nmi_unblock : 1; // something to do with NMIs and IRETs (Intel 3B, sec. 23.2.2) + uint32_t rsvd : 18; // always 0 + uint32_t valid : 1; // always 1 if valid + } __attribute__ ((packed)); + } __attribute__ ((packed)); +} __attribute__((packed)); + +/* VMX entry interrupt format */ +struct vmx_entry_int_info { + union { + uint32_t value; + struct { + uint32_t vector : 8; // IRQ/exception vector number + uint32_t type : 3; // (0: ext. IRQ, 2: NMI, 3: hw excp, 4: sw int, 5: priv. sw excp, 6: sw excp, 7: other + uint32_t error_code : 1; // 1: deliver error code + uint32_t rsvd : 19; + uint32_t valid : 1; // 1: valid + } __attribute__ ((packed)); + } __attribute__ ((packed)); +} __attribute__ ((packed)); + + struct VMExitDBGQual { @@ -110,14 +158,19 @@ struct VMExitTSQual { uint32_t src : 2; // (0: CALL ; 1: IRET ; 2: JMP ; 3: Task gate in IDT) } __attribute__((packed)); -struct vmexit_cr_qual { - uint32_t cr_id : 4; // cr number (0 for CLTS and LMSW) (bit 3 always 0, on 32bit) - uint32_t access_type : 2; // (0: MOV to CR ; 1: MOV from CR ; 2: CLTS ; 3: LMSW) - uint32_t lmsw_op_type : 1; // (0: register ; 1: memory) - uint32_t rsvd1 : 1; // reserved to 0 - uint32_t gpr : 4; // (0:RAX+[CLTS/LMSW], 1:RCX, 2:RDX, 3:RBX, 4:RSP, 5:RBP, 6:RSI, 6:RDI, 8-15:64bit regs) - uint32_t rsvd2 : 4; // reserved to 0 - uint32_t lmsw_src : 16; // src data for lmsw +struct vmx_exit_cr_qual { + union { + uint32_t value; + struct { + uint32_t cr_id : 4; // cr number (0 for CLTS and LMSW) (bit 3 always 0, on 32bit) + uint32_t access_type : 2; // (0: MOV to CR ; 1: MOV from CR ; 2: CLTS ; 3: LMSW) + uint32_t lmsw_op_type : 1; // (0: register ; 1: memory) + uint32_t rsvd1 : 1; // reserved to 0 + uint32_t gpr : 4; // (0:RAX+[CLTS/LMSW], 1:RCX, 2:RDX, 3:RBX, 4:RSP, 5:RBP, 6:RSI, 6:RDI, 8-15:64bit regs) + uint32_t rsvd2 : 4; // reserved to 0 + uint32_t lmsw_src : 16; // src data for lmsw + } __attribute__((packed)); + } __attribute__((packed)); } __attribute__((packed)); struct VMExitMovDRQual { @@ -130,8 +183,22 @@ struct VMExitMovDRQual { /* End Exit Qualifications */ - -int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info); +struct vmx_exit_idt_vec_info { + union { + uint32_t value; + struct { + uint32_t vector : 8; + uint32_t type : 3; + uint32_t error_code : 1; + uint32_t undef : 1; + uint32_t rsvd : 18; + uint32_t valid : 1; + } __attribute__ ((packed)); + } __attribute__ ((packed)); +} __attribute__ ((packed)); + +int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info, struct v3_ctrl_regs * ctrl_regs); +const char * v3_vmx_exit_code_to_str(vmx_exit_t exit); #endif diff --git a/palacios/src/devices/8259a.c b/palacios/src/devices/8259a.c index 8019f82..4b70979 100644 --- a/palacios/src/devices/8259a.c +++ b/palacios/src/devices/8259a.c @@ -292,31 +292,31 @@ static int pic_get_intr_number(void * private_data) { /* The IRQ number is the number returned by pic_get_intr_number(), not the pin number */ static int pic_begin_irq(void * private_data, int irq) { struct pic_internal * state = (struct pic_internal*)private_data; - + if ((irq >= state->master_icw2) && (irq <= state->master_icw2 + 7)) { - irq &= 0x7; + irq &= 0x7; } else if ((irq >= state->slave_icw2) && (irq <= state->slave_icw2 + 7)) { - irq &= 0x7; - irq += 8; + irq &= 0x7; + irq += 8; } else { - // PrintError("8259 PIC: Could not find IRQ (0x%x) to Begin\n",irq); - return -1; + // PrintError("8259 PIC: Could not find IRQ (0x%x) to Begin\n",irq); + return -1; } - + if (irq <= 7) { - if (((state->master_irr & ~(state->master_imr)) >> irq) == 0x01) { - state->master_isr |= (0x1 << irq); + if (((state->master_irr & ~(state->master_imr)) >> irq) == 0x01) { + state->master_isr |= (0x1 << irq); - if (!(state->master_elcr & (0x1 << irq))) { - state->master_irr &= ~(0x1 << irq); - } - } + if (!(state->master_elcr & (0x1 << irq))) { + state->master_irr &= ~(0x1 << irq); + } + } } else { - state->slave_isr |= (0x1 << (irq - 8)); + state->slave_isr |= (0x1 << (irq - 8)); - if (!(state->slave_elcr & (0x1 << irq))) { - state->slave_irr &= ~(0x1 << (irq - 8)); - } + if (!(state->slave_elcr & (0x1 << irq))) { + state->slave_irr &= ~(0x1 << (irq - 8)); + } } return 0; diff --git a/palacios/src/devices/apic.c b/palacios/src/devices/apic.c index 6fdce71..34ac432 100644 --- a/palacios/src/devices/apic.c +++ b/palacios/src/devices/apic.c @@ -236,9 +236,8 @@ static void init_apic_state(struct apic_state * apic) { static int read_apic_msr(uint_t msr, v3_msr_t * dst, void * priv_data) { struct vm_device * dev = (struct vm_device *)priv_data; struct apic_state * apic = (struct apic_state *)dev->private_data; - PrintError("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_msr.hi, apic->base_addr_msr.lo); - - return -1; + dst->value = apic->base_addr; + return 0; } diff --git a/palacios/src/devices/ide.c b/palacios/src/devices/ide.c index e11944f..363641a 100644 --- a/palacios/src/devices/ide.c +++ b/palacios/src/devices/ide.c @@ -280,9 +280,9 @@ static inline int is_lba_enabled(struct ide_channel * channel) { /* Drive Commands */ static void ide_raise_irq(struct vm_device * dev, struct ide_channel * channel) { if (channel->ctrl_reg.irq_disable == 0) { - PrintDebug("Raising IDE Interrupt %d\n", channel->irq); - channel->dma_status.int_gen = 1; - v3_raise_irq(dev->vm, channel->irq); + PrintError("Raising IDE Interrupt %d\n", channel->irq); + channel->dma_status.int_gen = 1; + v3_raise_irq(dev->vm, channel->irq); } } diff --git a/palacios/src/devices/piix3.c b/palacios/src/devices/piix3.c index 73fd46c..8b2f627 100644 --- a/palacios/src/devices/piix3.c +++ b/palacios/src/devices/piix3.c @@ -367,7 +367,7 @@ static int raise_pci_irq(struct vm_device * dev, struct pci_device * pci_dev) { int intr_pin = pci_dev->config_header.intr_pin - 1; int irq_index = (intr_pin + pci_dev->dev_num - 1) & 0x3; - // PrintError("Raising PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]); + PrintError("Raising PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]); v3_raise_irq(dev->vm, piix3_cfg->pirq_rc[irq_index]); diff --git a/palacios/src/palacios/Makefile b/palacios/src/palacios/Makefile index fb2623e..cc33662 100644 --- a/palacios/src/palacios/Makefile +++ b/palacios/src/palacios/Makefile @@ -10,6 +10,7 @@ obj-y := \ vmm_direct_paging.o \ vmm_emulator.o \ vmm_excp.o \ + vmm_halt.o \ vmm_hashtable.o \ vmm_host_events.o \ vmm_hypercall.o \ @@ -32,7 +33,6 @@ obj-y := \ obj-$(CONFIG_SVM) += svm.o \ - svm_halt.o \ svm_io.o \ svm_lowlevel.o \ svm_msr.o \ @@ -56,4 +56,4 @@ obj-$(CONFIG_INSTRUMENT_VMM) += vmm_instrument.o obj-$(CONFIG_TELEMETRY) += vmm_telemetry.o obj-$(CONFIG_SOCKET) += vmm_socket.o -obj-$(CONFIG_SYMBIOTIC_SWAP) += vmm_sym_swap.o \ No newline at end of file +obj-$(CONFIG_SYMBIOTIC_SWAP) += vmm_sym_swap.o diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index 30d581e..5736234 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -264,7 +264,7 @@ int v3_handle_svm_exit(struct guest_info * info) { #ifdef CONFIG_DEBUG_HALT PrintDebug("Guest halted\n"); #endif - if (v3_handle_svm_halt(info) == -1) { + if (v3_handle_halt(info) == -1) { return -1; } break; diff --git a/palacios/src/palacios/svm_msr.c b/palacios/src/palacios/svm_msr.c index dcc653e..8e59658 100644 --- a/palacios/src/palacios/svm_msr.c +++ b/palacios/src/palacios/svm_msr.c @@ -88,54 +88,3 @@ int v3_init_svm_msr_map(struct guest_info * info) { } - -int v3_handle_msr_write(struct guest_info * info) { - uint_t msr_num = info->vm_regs.rcx; - struct v3_msr msr_val; - struct v3_msr_hook * hook = NULL; - - hook = v3_get_msr_hook(info, msr_num); - - if (!hook) { - PrintError("Hook for MSR write %d not found\n", msr_num); - return -1; - } - - msr_val.value = 0; - msr_val.lo = info->vm_regs.rax; - msr_val.hi = info->vm_regs.rdx; - - if (hook->write(msr_num, msr_val, hook->priv_data) == -1) { - PrintError("Error in MSR hook Write\n"); - return -1; - } - - return 0; -} - - - -int v3_handle_msr_read(struct guest_info * info) { - uint_t msr_num = info->vm_regs.rcx; - struct v3_msr msr_val; - struct v3_msr_hook * hook = NULL; - - hook = v3_get_msr_hook(info, msr_num); - - if (!hook) { - PrintError("Hook for MSR read %d not found\n", msr_num); - return -1; - } - - msr_val.value = 0; - - if (hook->read(msr_num, &msr_val, hook->priv_data) == -1) { - PrintError("Error in MSR hook Read\n"); - return -1; - } - - info->vm_regs.rax = msr_val.lo; - info->vm_regs.rdx = msr_val.hi; - - return 0; -} diff --git a/palacios/src/palacios/vmcs.c b/palacios/src/palacios/vmcs.c index e5de8e3..e7f9570 100644 --- a/palacios/src/palacios/vmcs.c +++ b/palacios/src/palacios/vmcs.c @@ -20,7 +20,62 @@ #include #include #include +#include +#include +#include +#include +static void inline translate_v3_seg_to_access(struct v3_segment * v3_seg, + struct vmcs_segment_access * access) +{ + access->type = v3_seg->type; + access->desc_type = v3_seg->system; + access->dpl = v3_seg->dpl; + access->present = v3_seg->present; + access->avail = v3_seg->avail; + access->long_mode = v3_seg->long_mode; + access->db = v3_seg->db; + access->granularity = v3_seg->granularity; +} + +static void inline translate_access_to_v3_seg(struct vmcs_segment_access * access, + struct v3_segment * v3_seg) +{ + v3_seg->type = access->type; + v3_seg->system = access->desc_type; + v3_seg->dpl = access->dpl; + v3_seg->present = access->present; + v3_seg->avail = access->avail; + v3_seg->long_mode = access->long_mode; + v3_seg->db = access->db; + v3_seg->granularity = access->granularity; +} + + +static int inline check_vmcs_write(vmcs_field_t field, addr_t val) +{ + int ret = 0; + ret = vmcs_write(field, val); + + if (ret != VMX_SUCCESS) { + PrintError("VMWRITE error on %s!: %d\n", v3_vmcs_field_to_str(field), ret); + return 1; + } + + return 0; +} + +static int inline check_vmcs_read(vmcs_field_t field, void * val) +{ + int ret = 0; + ret = vmcs_read(field, val); + + if (ret != VMX_SUCCESS) { + PrintError("VMREAD error on %s!: %d\n", v3_vmcs_field_to_str(field), ret); + } + + return ret; +} // static const char * v3_vmcs_field_to_str(vmcs_field_t field); @@ -29,6 +84,335 @@ // Ignores "HIGH" addresses - 32 bit only for now // +int v3_update_vmcs_guest_state(struct guest_info * info) +{ + int vmx_ret = 0; + + vmx_ret |= check_vmcs_write(VMCS_GUEST_RIP, info->rip); + vmx_ret |= check_vmcs_write(VMCS_GUEST_RSP, info->vm_regs.rsp); + + + vmx_ret |= check_vmcs_write(VMCS_GUEST_CR0, info->ctrl_regs.cr0); + vmx_ret |= check_vmcs_write(VMCS_CR0_READ_SHDW, info->shdw_pg_state.guest_cr0); + vmx_ret |= check_vmcs_write(VMCS_GUEST_CR3, info->ctrl_regs.cr3); + vmx_ret |= check_vmcs_write(VMCS_GUEST_CR4, info->ctrl_regs.cr4); + vmx_ret |= check_vmcs_write(VMCS_GUEST_DR7, info->dbg_regs.dr7); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_RFLAGS, info->ctrl_regs.rflags); + if (((struct vmx_data *)info->vmm_data)->ia32e_avail) { + vmx_ret |= check_vmcs_write(VMCS_GUEST_EFER, info->ctrl_regs.efer); + } + + + /*** Write VMCS Segments ***/ + struct vmcs_segment_access access; + + memset(&access, 0, sizeof(access)); + + /* CS Segment */ + translate_v3_seg_to_access(&(info->segments.cs), &access); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_BASE, info->segments.cs.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_SELECTOR, info->segments.cs.selector); + vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_LIMIT, info->segments.cs.limit); + vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_ACCESS, access.value); + + /* SS Segment */ + memset(&access, 0, sizeof(access)); + translate_v3_seg_to_access(&(info->segments.ss), &access); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_BASE, info->segments.ss.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_SELECTOR, info->segments.ss.selector); + vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_LIMIT, info->segments.ss.limit); + vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_ACCESS, access.value); + + /* DS Segment */ + memset(&access, 0, sizeof(access)); + translate_v3_seg_to_access(&(info->segments.ds), &access); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_BASE, info->segments.ds.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_SELECTOR, info->segments.ds.selector); + vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_LIMIT, info->segments.ds.limit); + vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_ACCESS, access.value); + + + /* ES Segment */ + memset(&access, 0, sizeof(access)); + translate_v3_seg_to_access(&(info->segments.es), &access); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_BASE, info->segments.es.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_SELECTOR, info->segments.es.selector); + vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_LIMIT, info->segments.es.limit); + vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_ACCESS, access.value); + + /* FS Segment */ + memset(&access, 0, sizeof(access)); + translate_v3_seg_to_access(&(info->segments.fs), &access); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_BASE, info->segments.fs.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_SELECTOR, info->segments.fs.selector); + vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_LIMIT, info->segments.fs.limit); + vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_ACCESS, access.value); + + /* GS Segment */ + memset(&access, 0, sizeof(access)); + translate_v3_seg_to_access(&(info->segments.gs), &access); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_BASE, info->segments.gs.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_SELECTOR, info->segments.gs.selector); + vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_LIMIT, info->segments.gs.limit); + vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_ACCESS, access.value); + + /* LDTR segment */ + memset(&access, 0, sizeof(access)); + translate_v3_seg_to_access(&(info->segments.ldtr), &access); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_BASE, info->segments.ldtr.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_SELECTOR, info->segments.ldtr.selector); + vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_LIMIT, info->segments.ldtr.limit); + vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_ACCESS, access.value); + + /* TR Segment */ + memset(&access, 0, sizeof(access)); + translate_v3_seg_to_access(&(info->segments.tr), &access); + + vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_BASE, info->segments.tr.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_SELECTOR, info->segments.tr.selector); + vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_LIMIT, info->segments.tr.limit); + vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_ACCESS, access.value); + + /* GDTR Segment */ + + vmx_ret |= check_vmcs_write(VMCS_GUEST_GDTR_BASE, info->segments.gdtr.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_GDTR_LIMIT, info->segments.gdtr.limit); + + /* IDTR Segment*/ + vmx_ret |= check_vmcs_write(VMCS_GUEST_IDTR_BASE, info->segments.idtr.base); + vmx_ret |= check_vmcs_write(VMCS_GUEST_IDTR_LIMIT, info->segments.idtr.limit); + + return vmx_ret; + +} + +int v3_update_vmcs_ctrl_fields(struct guest_info * info) { + int vmx_ret = 0; + struct vmx_data * arch_data = (struct vmx_data *)(info->vmm_data); + + vmx_ret |= check_vmcs_write(VMCS_PIN_CTRLS, arch_data->pin_ctrls.value); + vmx_ret |= check_vmcs_write(VMCS_PROC_CTRLS, arch_data->pri_proc_ctrls.value); + + if (arch_data->pri_proc_ctrls.sec_ctrls) { + vmx_ret |= check_vmcs_write(VMCS_SEC_PROC_CTRLS, arch_data->sec_proc_ctrls.value); + } + + vmx_ret |= check_vmcs_write(VMCS_EXIT_CTRLS, arch_data->exit_ctrls.value); + vmx_ret |= check_vmcs_write(VMCS_ENTRY_CTRLS, arch_data->entry_ctrls.value); + + return vmx_ret; +} + +int v3_update_vmcs_host_state(struct guest_info * info) { + int vmx_ret = 0; + addr_t tmp; + struct vmx_data * arch_data = (struct vmx_data *)(info->vmm_data); + struct v3_msr tmp_msr; + + __asm__ __volatile__ ( "movq %%cr0, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_CR0, tmp); + + + __asm__ __volatile__ ( "movq %%cr3, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_CR3, tmp); + + + __asm__ __volatile__ ( "movq %%cr4, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_CR4, tmp); + + + + vmx_ret |= check_vmcs_write(VMCS_HOST_GDTR_BASE, arch_data->host_state.gdtr.base); + vmx_ret |= check_vmcs_write(VMCS_HOST_IDTR_BASE, arch_data->host_state.idtr.base); + vmx_ret |= check_vmcs_write(VMCS_HOST_TR_BASE, arch_data->host_state.tr.base); + +#define FS_BASE_MSR 0xc0000100 +#define GS_BASE_MSR 0xc0000101 + + // FS.BASE MSR + v3_get_msr(FS_BASE_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); + vmx_ret |= check_vmcs_write(VMCS_HOST_FS_BASE, tmp_msr.value); + + // GS.BASE MSR + v3_get_msr(GS_BASE_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); + vmx_ret |= check_vmcs_write(VMCS_HOST_GS_BASE, tmp_msr.value); + + + + __asm__ __volatile__ ( "movq %%cs, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_CS_SELECTOR, tmp); + + __asm__ __volatile__ ( "movq %%ss, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_SS_SELECTOR, tmp); + + __asm__ __volatile__ ( "movq %%ds, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_DS_SELECTOR, tmp); + + __asm__ __volatile__ ( "movq %%es, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_ES_SELECTOR, tmp); + + __asm__ __volatile__ ( "movq %%fs, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_FS_SELECTOR, tmp); + + __asm__ __volatile__ ( "movq %%gs, %0; " + : "=q"(tmp) + : + ); + vmx_ret |= check_vmcs_write(VMCS_HOST_GS_SELECTOR, tmp); + + vmx_ret |= check_vmcs_write(VMCS_HOST_TR_SELECTOR, arch_data->host_state.tr.selector); + + +#define SYSENTER_CS_MSR 0x00000174 +#define SYSENTER_ESP_MSR 0x00000175 +#define SYSENTER_EIP_MSR 0x00000176 + + // SYSENTER CS MSR + v3_get_msr(SYSENTER_CS_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); + vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_CS, tmp_msr.lo); + + // SYSENTER_ESP MSR + v3_get_msr(SYSENTER_ESP_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); + vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_ESP, tmp_msr.value); + + // SYSENTER_EIP MSR + v3_get_msr(SYSENTER_EIP_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); + vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_EIP, tmp_msr.value); + + return vmx_ret; +} + + +int v3_load_vmcs_guest_state(struct guest_info * info) +{ + + int error = 0; + + check_vmcs_read(VMCS_GUEST_RIP, &(info->rip)); + check_vmcs_read(VMCS_GUEST_RSP, &(info->vm_regs.rsp)); + + check_vmcs_read(VMCS_GUEST_CR0, &(info->ctrl_regs.cr0)); + check_vmcs_read(VMCS_CR0_READ_SHDW, &(info->shdw_pg_state.guest_cr0)); + check_vmcs_read(VMCS_GUEST_CR3, &(info->ctrl_regs.cr3)); + check_vmcs_read(VMCS_GUEST_CR4, &(info->ctrl_regs.cr4)); + check_vmcs_read(VMCS_GUEST_DR7, &(info->dbg_regs.dr7)); + + check_vmcs_read(VMCS_GUEST_RFLAGS, &(info->ctrl_regs.rflags)); + if (((struct vmx_data *)info->vmm_data)->ia32e_avail) { + check_vmcs_read(VMCS_GUEST_EFER, &(info->ctrl_regs.efer)); + } + + // JRL: Add error checking + + struct vmcs_segment_access access; + memset(&access, 0, sizeof(access)); + + /* CS Segment */ + check_vmcs_read(VMCS_GUEST_CS_BASE, &(info->segments.cs.base)); + check_vmcs_read(VMCS_GUEST_CS_SELECTOR, &(info->segments.cs.selector)); + check_vmcs_read(VMCS_GUEST_CS_LIMIT, &(info->segments.cs.limit)); + check_vmcs_read(VMCS_GUEST_CS_ACCESS, &(access.value)); + + translate_access_to_v3_seg(&access, &(info->segments.cs)); + + /* SS Segment */ + check_vmcs_read(VMCS_GUEST_SS_BASE, &(info->segments.ss.base)); + check_vmcs_read(VMCS_GUEST_SS_SELECTOR, &(info->segments.ss.selector)); + check_vmcs_read(VMCS_GUEST_SS_LIMIT, &(info->segments.ss.limit)); + check_vmcs_read(VMCS_GUEST_SS_ACCESS, &(access.value)); + + translate_access_to_v3_seg(&access, &(info->segments.ss)); + + /* DS Segment */ + check_vmcs_read(VMCS_GUEST_DS_BASE, &(info->segments.ds.base)); + check_vmcs_read(VMCS_GUEST_DS_SELECTOR, &(info->segments.ds.selector)); + check_vmcs_read(VMCS_GUEST_DS_LIMIT, &(info->segments.ds.limit)); + check_vmcs_read(VMCS_GUEST_DS_ACCESS, &(access.value)); + + translate_access_to_v3_seg(&access, &(info->segments.ds)); + + /* ES Segment */ + check_vmcs_read(VMCS_GUEST_ES_BASE, &(info->segments.es.base)); + check_vmcs_read(VMCS_GUEST_ES_SELECTOR, &(info->segments.es.selector)); + check_vmcs_read(VMCS_GUEST_ES_LIMIT, &(info->segments.es.limit)); + check_vmcs_read(VMCS_GUEST_ES_ACCESS, &(access.value)); + + translate_access_to_v3_seg(&access, &(info->segments.es)); + + /* FS Segment */ + check_vmcs_read(VMCS_GUEST_FS_BASE, &(info->segments.fs.base)); + check_vmcs_read(VMCS_GUEST_FS_SELECTOR, &(info->segments.fs.selector)); + check_vmcs_read(VMCS_GUEST_FS_LIMIT, &(info->segments.fs.limit)); + check_vmcs_read(VMCS_GUEST_FS_ACCESS, &(access.value)); + + translate_access_to_v3_seg(&access, &(info->segments.fs)); + + /* GS Segment */ + check_vmcs_read(VMCS_GUEST_GS_BASE, &(info->segments.gs.base)); + check_vmcs_read(VMCS_GUEST_GS_SELECTOR, &(info->segments.gs.selector)); + check_vmcs_read(VMCS_GUEST_GS_LIMIT, &(info->segments.gs.limit)); + check_vmcs_read(VMCS_GUEST_GS_ACCESS, &(access.value)); + + translate_access_to_v3_seg(&access, &(info->segments.gs)); + + /* LDTR Segment */ + check_vmcs_read(VMCS_GUEST_LDTR_BASE, &(info->segments.ldtr.base)); + check_vmcs_read(VMCS_GUEST_LDTR_SELECTOR, &(info->segments.ldtr.selector)); + check_vmcs_read(VMCS_GUEST_LDTR_LIMIT, &(info->segments.ldtr.limit)); + check_vmcs_read(VMCS_GUEST_LDTR_ACCESS, &(access.value)); + + translate_access_to_v3_seg(&access, &(info->segments.ldtr)); + + /* TR Segment */ + check_vmcs_read(VMCS_GUEST_TR_BASE, &(info->segments.tr.base)); + check_vmcs_read(VMCS_GUEST_TR_SELECTOR, &(info->segments.tr.selector)); + check_vmcs_read(VMCS_GUEST_TR_LIMIT, &(info->segments.tr.limit)); + check_vmcs_read(VMCS_GUEST_TR_ACCESS, &(access.value)); + + translate_access_to_v3_seg(&access, &(info->segments.tr)); + + /* GDTR Segment */ + check_vmcs_read(VMCS_GUEST_GDTR_BASE, &(info->segments.gdtr.base)); + check_vmcs_read(VMCS_GUEST_GDTR_LIMIT, &(info->segments.gdtr.limit)); + + /* IDTR Segment */ + check_vmcs_read(VMCS_GUEST_IDTR_BASE, &(info->segments.idtr.base)); + check_vmcs_read(VMCS_GUEST_IDTR_LIMIT, &(info->segments.idtr.limit)); + + return error; +} static inline void print_vmcs_field(vmcs_field_t vmcs_index) { int len = v3_vmcs_get_field_len(vmcs_index); @@ -302,7 +686,7 @@ static void print_exit_info() { print_vmcs_field(VMCS_EXIT_INSTR_LEN); print_vmcs_field(VMCS_GUEST_LINEAR_ADDR); - print_vmcs_field(VMCS_VMX_INSTR_INFO); + print_vmcs_field(VMCS_EXIT_INSTR_INFO); print_vmcs_field(VMCS_IO_RCX); print_vmcs_field(VMCS_IO_RSI); @@ -381,7 +765,7 @@ int v3_vmcs_get_field_len(vmcs_field_t field) { case VMCS_IDT_VECTOR_INFO: case VMCS_IDT_VECTOR_ERR: case VMCS_EXIT_INSTR_LEN: - case VMCS_VMX_INSTR_INFO: + case VMCS_EXIT_INSTR_INFO: case VMCS_GUEST_ES_LIMIT: case VMCS_GUEST_CS_LIMIT: case VMCS_GUEST_SS_LIMIT: @@ -573,7 +957,7 @@ static const char VMCS_EXIT_INT_ERR_STR[] = "VM_EXIT_INT_ERROR"; static const char VMCS_IDT_VECTOR_INFO_STR[] = "IDT_VECTOR_INFO"; static const char VMCS_IDT_VECTOR_ERR_STR[] = "IDT_VECTOR_ERROR"; static const char VMCS_EXIT_INSTR_LEN_STR[] = "VM_EXIT_INSTR_LENGTH"; -static const char VMCS_VMX_INSTR_INFO_STR[] = "VMX_INSTR_INFO"; +static const char VMCS_EXIT_INSTR_INFO_STR[] = "VMX_INSTR_INFO"; static const char VMCS_GUEST_ES_LIMIT_STR[] = "GUEST_ES_LIMIT"; static const char VMCS_GUEST_CS_LIMIT_STR[] = "GUEST_CS_LIMIT"; static const char VMCS_GUEST_SS_LIMIT_STR[] = "GUEST_SS_LIMIT"; @@ -780,8 +1164,8 @@ const char * v3_vmcs_field_to_str(vmcs_field_t field) { return VMCS_IDT_VECTOR_ERR_STR; case VMCS_EXIT_INSTR_LEN: return VMCS_EXIT_INSTR_LEN_STR; - case VMCS_VMX_INSTR_INFO: - return VMCS_VMX_INSTR_INFO_STR; + case VMCS_EXIT_INSTR_INFO: + return VMCS_EXIT_INSTR_INFO_STR; case VMCS_GUEST_ES_LIMIT: return VMCS_GUEST_ES_LIMIT_STR; case VMCS_GUEST_CS_LIMIT: diff --git a/palacios/src/palacios/vmm_ctrl_regs.c b/palacios/src/palacios/vmm_ctrl_regs.c index 5476635..2b20972 100644 --- a/palacios/src/palacios/vmm_ctrl_regs.c +++ b/palacios/src/palacios/vmm_ctrl_regs.c @@ -547,7 +547,6 @@ int v3_handle_efer_read(uint_t msr, struct v3_msr * dst, void * priv_data) { dst->value = info->shdw_pg_state.guest_efer.value; - info->rip += 2; // WRMSR/RDMSR are two byte operands return 0; } @@ -571,7 +570,5 @@ int v3_handle_efer_write(uint_t msr, struct v3_msr src, void * priv_data) { // Enable/Disable Syscall shadow_efer->sce = src.value & 0x1; - info->rip += 2; // WRMSR/RDMSR are two byte operands - return 0; } diff --git a/palacios/src/palacios/vmm_direct_paging_32.h b/palacios/src/palacios/vmm_direct_paging_32.h index c71baf0..52f0991 100644 --- a/palacios/src/palacios/vmm_direct_paging_32.h +++ b/palacios/src/palacios/vmm_direct_paging_32.h @@ -63,7 +63,7 @@ static inline int handle_passthrough_pagefault_32(struct guest_info * info, pde[pde_index].present = 1; pde[pde_index].writable = 1; - pde[pde_index].user_page = 0; + pde[pde_index].user_page = 1; pde[pde_index].pt_base_addr = PAGE_BASE_ADDR((addr_t)V3_PAddr(pte)); } else { @@ -73,7 +73,7 @@ static inline int handle_passthrough_pagefault_32(struct guest_info * info, // Fix up the PTE entry if (pte[pte_index].present == 0) { - pte[pte_index].user_page = 0; + pte[pte_index].user_page = 1; if (region->host_type == SHDW_REGION_ALLOCATED) { // Full access diff --git a/palacios/src/palacios/svm_halt.c b/palacios/src/palacios/vmm_halt.c similarity index 94% rename from palacios/src/palacios/svm_halt.c rename to palacios/src/palacios/vmm_halt.c index a8bf0b9..2be016c 100644 --- a/palacios/src/palacios/svm_halt.c +++ b/palacios/src/palacios/vmm_halt.c @@ -18,7 +18,7 @@ * redistribute, and modify it as specified in the file "V3VEE_LICENSE". */ -#include +#include #include @@ -33,7 +33,7 @@ // This should trigger a #GP if cpl != 0, otherwise, yield to host // -int v3_handle_svm_halt(struct guest_info * info) { +int v3_handle_halt(struct guest_info * info) { if (info->cpl != 0) { v3_raise_exception(info, GPF_EXCEPTION); @@ -69,7 +69,7 @@ int v3_handle_svm_halt(struct guest_info * info) { PrintDebug("CPU Yield Done (%d cycles)\n", gap); - info->rip+=1; + info->rip += 1; } return 0; diff --git a/palacios/src/palacios/vmm_msr.c b/palacios/src/palacios/vmm_msr.c index 5fe5ffd..99ebf15 100644 --- a/palacios/src/palacios/vmm_msr.c +++ b/palacios/src/palacios/vmm_msr.c @@ -33,6 +33,58 @@ void v3_init_msr_map(struct guest_info * info) { msr_map->update_map = NULL; } +int v3_handle_msr_write(struct guest_info * info) { + uint_t msr_num = info->vm_regs.rcx; + struct v3_msr msr_val; + struct v3_msr_hook * hook = NULL; + + hook = v3_get_msr_hook(info, msr_num); + + if (!hook) { + PrintError("Hook for MSR write %d not found\n", msr_num); + return -1; + } + + msr_val.value = 0; + msr_val.lo = info->vm_regs.rax; + msr_val.hi = info->vm_regs.rdx; + + if (hook->write(msr_num, msr_val, hook->priv_data) == -1) { + PrintError("Error in MSR hook Write\n"); + return -1; + } + + info->rip += 2; + + return 0; +} + + +int v3_handle_msr_read(struct guest_info * info) { + uint_t msr_num = info->vm_regs.rcx; + struct v3_msr msr_val; + struct v3_msr_hook * hook = NULL; + + hook = v3_get_msr_hook(info, msr_num); + + if (!hook) { + PrintError("Hook for MSR read %d not found\n", msr_num); + return -1; + } + + msr_val.value = 0; + + if (hook->read(msr_num, &msr_val, hook->priv_data) == -1) { + PrintError("Error in MSR hook Read\n"); + return -1; + } + + info->vm_regs.rax = msr_val.lo; + info->vm_regs.rdx = msr_val.hi; + + info->rip += 2; + return 0; +} int v3_hook_msr(struct guest_info * info, uint_t msr, int (*read)(uint_t msr, struct v3_msr * dst, void * priv_data), diff --git a/palacios/src/palacios/vmx.c b/palacios/src/palacios/vmx.c index 226839c..4f8abec 100644 --- a/palacios/src/palacios/vmx.c +++ b/palacios/src/palacios/vmx.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -33,11 +34,11 @@ static addr_t vmxon_ptr_phys; extern int v3_vmx_exit_handler(); -extern int v3_vmx_vmlaunch(struct v3_gprs * vm_regs, struct guest_info * info); +extern int v3_vmx_vmlaunch(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) -{ +static int inline check_vmcs_write(vmcs_field_t field, addr_t val) { int ret = 0; + ret = vmcs_write(field,val); if (ret != VMX_SUCCESS) { @@ -48,249 +49,6 @@ static int inline check_vmcs_write(vmcs_field_t field, addr_t val) return 0; } -static void inline translate_segment_access(struct v3_segment * v3_seg, - struct vmcs_segment_access * access) -{ - access->type = v3_seg->type; - access->desc_type = v3_seg->system; - access->dpl = v3_seg->dpl; - access->present = v3_seg->present; - access->avail = v3_seg->avail; - access->long_mode = v3_seg->long_mode; - access->db = v3_seg->db; - access->granularity = v3_seg->granularity; -} - -int v3_update_vmcs_ctrl_fields(struct guest_info * info) { - int vmx_ret = 0; - struct vmx_data * arch_data = (struct vmx_data *)(info->vmm_data); - - vmx_ret |= check_vmcs_write(VMCS_PIN_CTRLS, arch_data->pinbased_ctrls); - vmx_ret |= check_vmcs_write(VMCS_PROC_CTRLS, arch_data->pri_procbased_ctrls); - - if(arch_data->pri_procbased_ctrls & ACTIVE_SEC_CTRLS) { - vmx_ret |= check_vmcs_write(VMCS_SEC_PROC_CTRLS, arch_data->sec_procbased_ctrls); - } - - vmx_ret |= check_vmcs_write(VMCS_EXIT_CTRLS, arch_data->exit_ctrls); - vmx_ret |= check_vmcs_write(VMCS_ENTRY_CTRLS, arch_data->entry_ctrls); - - return vmx_ret; -} - -int v3_update_vmcs_host_state(struct guest_info * info) { - int vmx_ret = 0; - addr_t tmp; - struct vmx_data * arch_data = (struct vmx_data *)(info->vmm_data); - struct v3_msr tmp_msr; - - __asm__ __volatile__ ( "movq %%cr0, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_CR0, tmp); - - - __asm__ __volatile__ ( "movq %%cr3, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_CR3, tmp); - - - __asm__ __volatile__ ( "movq %%cr4, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_CR4, tmp); - - - - vmx_ret |= check_vmcs_write(VMCS_HOST_GDTR_BASE, arch_data->host_state.gdtr.base); - vmx_ret |= check_vmcs_write(VMCS_HOST_IDTR_BASE, arch_data->host_state.idtr.base); - vmx_ret |= check_vmcs_write(VMCS_HOST_TR_BASE, arch_data->host_state.tr.base); - -#define FS_BASE_MSR 0xc0000100 -#define GS_BASE_MSR 0xc0000101 - - // FS.BASE MSR - v3_get_msr(FS_BASE_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); - vmx_ret |= check_vmcs_write(VMCS_HOST_FS_BASE, tmp_msr.value); - - // GS.BASE MSR - v3_get_msr(GS_BASE_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); - vmx_ret |= check_vmcs_write(VMCS_HOST_GS_BASE, tmp_msr.value); - - - - __asm__ __volatile__ ( "movq %%cs, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_CS_SELECTOR, tmp); - - __asm__ __volatile__ ( "movq %%ss, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_SS_SELECTOR, tmp); - - __asm__ __volatile__ ( "movq %%ds, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_DS_SELECTOR, tmp); - - __asm__ __volatile__ ( "movq %%es, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_ES_SELECTOR, tmp); - - __asm__ __volatile__ ( "movq %%fs, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_FS_SELECTOR, tmp); - - __asm__ __volatile__ ( "movq %%gs, %0; " - : "=q"(tmp) - : - ); - vmx_ret |= check_vmcs_write(VMCS_HOST_GS_SELECTOR, tmp); - - vmx_ret |= check_vmcs_write(VMCS_HOST_TR_SELECTOR, arch_data->host_state.tr.selector); - - -#define SYSENTER_CS_MSR 0x00000174 -#define SYSENTER_ESP_MSR 0x00000175 -#define SYSENTER_EIP_MSR 0x00000176 - - // SYSENTER CS MSR - v3_get_msr(SYSENTER_CS_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); - vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_CS, tmp_msr.lo); - - // SYSENTER_ESP MSR - v3_get_msr(SYSENTER_ESP_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); - vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_ESP, tmp_msr.value); - - // SYSENTER_EIP MSR - v3_get_msr(SYSENTER_EIP_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); - vmx_ret |= check_vmcs_write(VMCS_HOST_SYSENTER_EIP, tmp_msr.value); - - return vmx_ret; -} - - -int v3_update_vmcs_guest_state(struct guest_info * info) -{ - int vmx_ret = 0; - - vmx_ret |= check_vmcs_write(VMCS_GUEST_RIP, info->rip); - vmx_ret |= check_vmcs_write(VMCS_GUEST_RSP, info->vm_regs.rsp); - - - vmx_ret |= check_vmcs_write(VMCS_GUEST_CR0, info->ctrl_regs.cr0); - vmx_ret |= check_vmcs_write(VMCS_GUEST_CR3, info->ctrl_regs.cr3); - vmx_ret |= check_vmcs_write(VMCS_GUEST_CR4, info->ctrl_regs.cr4); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_RFLAGS, info->ctrl_regs.rflags); - - - - /*** Write VMCS Segments ***/ - struct vmcs_segment_access access; - - memset(&access, 0, sizeof(access)); - - /* CS Segment */ - translate_segment_access(&(info->segments.cs), &access); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_BASE, info->segments.cs.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_SELECTOR, info->segments.cs.selector); - vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_LIMIT, info->segments.cs.limit); - vmx_ret |= check_vmcs_write(VMCS_GUEST_CS_ACCESS, access.value); - - /* SS Segment */ - memset(&access, 0, sizeof(access)); - translate_segment_access(&(info->segments.ss), &access); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_BASE, info->segments.ss.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_SELECTOR, info->segments.ss.selector); - vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_LIMIT, info->segments.ss.limit); - vmx_ret |= check_vmcs_write(VMCS_GUEST_SS_ACCESS, access.value); - - /* DS Segment */ - memset(&access, 0, sizeof(access)); - translate_segment_access(&(info->segments.ds), &access); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_BASE, info->segments.ds.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_SELECTOR, info->segments.ds.selector); - vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_LIMIT, info->segments.ds.limit); - vmx_ret |= check_vmcs_write(VMCS_GUEST_DS_ACCESS, access.value); - - - /* ES Segment */ - memset(&access, 0, sizeof(access)); - translate_segment_access(&(info->segments.es), &access); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_BASE, info->segments.es.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_SELECTOR, info->segments.es.selector); - vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_LIMIT, info->segments.es.limit); - vmx_ret |= check_vmcs_write(VMCS_GUEST_ES_ACCESS, access.value); - - /* FS Segment */ - memset(&access, 0, sizeof(access)); - translate_segment_access(&(info->segments.fs), &access); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_BASE, info->segments.fs.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_SELECTOR, info->segments.fs.selector); - vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_LIMIT, info->segments.fs.limit); - vmx_ret |= check_vmcs_write(VMCS_GUEST_FS_ACCESS, access.value); - - /* GS Segment */ - memset(&access, 0, sizeof(access)); - translate_segment_access(&(info->segments.gs), &access); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_BASE, info->segments.gs.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_SELECTOR, info->segments.gs.selector); - vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_LIMIT, info->segments.gs.limit); - vmx_ret |= check_vmcs_write(VMCS_GUEST_GS_ACCESS, access.value); - - /* LDTR segment */ - memset(&access, 0, sizeof(access)); - translate_segment_access(&(info->segments.ldtr), &access); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_BASE, info->segments.ldtr.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_SELECTOR, info->segments.ldtr.selector); - vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_LIMIT, info->segments.ldtr.limit); - vmx_ret |= check_vmcs_write(VMCS_GUEST_LDTR_ACCESS, access.value); - - /* TR Segment */ - memset(&access, 0, sizeof(access)); - translate_segment_access(&(info->segments.tr), &access); - - vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_BASE, info->segments.tr.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_SELECTOR, info->segments.tr.selector); - vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_LIMIT, info->segments.tr.limit); - vmx_ret |= check_vmcs_write(VMCS_GUEST_TR_ACCESS, access.value); - - /* GDTR Segment */ - - vmx_ret |= check_vmcs_write(VMCS_GUEST_GDTR_BASE, info->segments.gdtr.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_GDTR_LIMIT, info->segments.gdtr.limit); - - /* IDTR Segment*/ - vmx_ret |= check_vmcs_write(VMCS_GUEST_IDTR_BASE, info->segments.idtr.base); - vmx_ret |= check_vmcs_write(VMCS_GUEST_IDTR_LIMIT, info->segments.idtr.limit); - - return vmx_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 @@ -337,13 +95,13 @@ static addr_t sanitize_bits2(uint32_t msr_num0, uint32_t msr_num1, addr_t val) { #endif -static addr_t allocate_vmcs() -{ +static addr_t allocate_vmcs() { reg_ex_t msr; - PrintDebug("Allocating page\n"); - struct vmcs_data * vmcs_page = (struct vmcs_data *)V3_VAddr(V3_AllocPages(1)); + 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)); @@ -356,28 +114,28 @@ static addr_t allocate_vmcs() static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config_ptr) { - v3_pre_config_guest(info, config_ptr); + struct vmx_data * vmx_info = NULL; + int vmx_ret = 0; - struct vmx_data * vmx_data = NULL; + v3_pre_config_guest(info, config_ptr); - vmx_data = (struct vmx_data *)V3_Malloc(sizeof(struct vmx_data)); + vmx_info = (struct vmx_data *)V3_Malloc(sizeof(struct vmx_data)); - PrintDebug("vmx_data pointer: %p\n", (void *)vmx_data); + PrintDebug("vmx_data pointer: %p\n", (void *)vmx_info); PrintDebug("Allocating VMCS\n"); - vmx_data->vmcs_ptr_phys = allocate_vmcs(); + vmx_info->vmcs_ptr_phys = allocate_vmcs(); - PrintDebug("VMCS pointer: %p\n", (void *)(vmx_data->vmcs_ptr_phys)); + PrintDebug("VMCS pointer: %p\n", (void *)(vmx_info->vmcs_ptr_phys)); - info->vmm_data = vmx_data; + info->vmm_data = vmx_info; PrintDebug("Initializing VMCS (addr=%p)\n", info->vmm_data); // TODO: Fix vmcs fields so they're 32-bit - int vmx_ret = 0; - PrintDebug("Clearing VMCS: %p\n",(void*)vmx_data->vmcs_ptr_phys); - vmx_ret = vmcs_clear(vmx_data->vmcs_ptr_phys); + PrintDebug("Clearing VMCS: %p\n", (void *)vmx_info->vmcs_ptr_phys); + vmx_ret = vmcs_clear(vmx_info->vmcs_ptr_phys); if (vmx_ret != VMX_SUCCESS) { PrintError("VMCLEAR failed\n"); @@ -385,7 +143,7 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config } PrintDebug("Loading VMCS\n"); - vmx_ret = vmcs_load(vmx_data->vmcs_ptr_phys); + vmx_ret = vmcs_load(vmx_info->vmcs_ptr_phys); if (vmx_ret != VMX_SUCCESS) { PrintError("VMPTRLD failed\n"); @@ -411,7 +169,7 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config : "memory" ); gdtr_base = tmp_seg.base; - vmx_data->host_state.gdtr.base = gdtr_base; + vmx_info->host_state.gdtr.base = gdtr_base; __asm__ __volatile__( "sidt (%0);" @@ -419,7 +177,7 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config : "q"(&tmp_seg) : "memory" ); - vmx_data->host_state.idtr.base = tmp_seg.base; + vmx_info->host_state.idtr.base = tmp_seg.base; __asm__ __volatile__( "str (%0);" @@ -427,14 +185,13 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config : "q"(&tmp_seg) : "memory" ); - vmx_data->host_state.tr.selector = tmp_seg.selector; + vmx_info->host_state.tr.selector = tmp_seg.selector; /* The GDTR *index* is bits 3-15 of the selector. */ - struct tss_descriptor * desc = (struct tss_descriptor *) - (gdtr_base + 8*(tmp_seg.selector>>3)); + struct tss_descriptor * desc = NULL; + desc = (struct tss_descriptor *)(gdtr_base + (8 * (tmp_seg.selector >> 3))); - tmp_seg.base = ( - (desc->base1) | + tmp_seg.base = ((desc->base1) | (desc->base2 << 16) | (desc->base3 << 24) | #ifdef __V3_64BIT__ @@ -442,27 +199,34 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config #else (0) #endif - ); + ); - vmx_data->host_state.tr.base = tmp_seg.base; + vmx_info->host_state.tr.base = tmp_seg.base; /********** Setup and VMX Control Fields from MSR ***********/ /* Setup IO map */ - (void) v3_init_vmx_io_map(info); - (void) v3_init_vmx_msr_map(info); + v3_init_vmx_io_map(info); + v3_init_vmx_msr_map(info); struct v3_msr tmp_msr; - v3_get_msr(VMX_PINBASED_CTLS_MSR,&(tmp_msr.hi),&(tmp_msr.lo)); - /* Add NMI exiting */ - vmx_data->pinbased_ctrls = tmp_msr.lo | NMI_EXIT; + v3_get_msr(VMX_PINBASED_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); + + /* Add external interrupts, NMI exiting, and virtual NMI */ + vmx_info->pin_ctrls.value = tmp_msr.lo; + vmx_info->pin_ctrls.nmi_exit = 1; + vmx_info->pin_ctrls.ext_int_exit = 1; v3_get_msr(VMX_PROCBASED_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); - PrintDebug("MSR High: 0x%x\n", tmp_msr.hi); - vmx_data->pri_procbased_ctrls = tmp_msr.lo | USE_IO_BITMAPS ; + vmx_info->pri_proc_ctrls.value = tmp_msr.lo; + vmx_info->pri_proc_ctrls.use_io_bitmap = 1; + vmx_info->pri_proc_ctrls.hlt_exit = 1; + vmx_info->pri_proc_ctrls.invlpg_exit = 1; + vmx_info->pri_proc_ctrls.use_msr_bitmap = 1; + vmx_info->pri_proc_ctrls.pause_exit = 1; vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_A_ADDR, (addr_t)V3_PAddr(info->io_map.arch_data)); vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_B_ADDR, @@ -471,17 +235,24 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config vmx_ret |= check_vmcs_write(VMCS_MSR_BITMAP, (addr_t)V3_PAddr(info->msr_map.arch_data)); v3_get_msr(VMX_EXIT_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); - vmx_data->exit_ctrls = tmp_msr.lo ; - - v3_get_msr(VMX_ENTRY_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); - vmx_data->entry_ctrls = tmp_msr.lo; + vmx_info->exit_ctrls.value = tmp_msr.lo; + vmx_info->exit_ctrls.host_64_on = 1; - struct vmx_exception_bitmap excp_bmap; - excp_bmap.value = 0xffffffff; - excp_bmap.gp = 0; - vmx_ret |= check_vmcs_write(VMCS_EXCP_BITMAP, excp_bmap.value); + if ((vmx_info->exit_ctrls.save_efer == 1) || (vmx_info->exit_ctrls.ld_efer == 1)) { + vmx_info->ia32e_avail = 1; + } + v3_get_msr(VMX_ENTRY_CTLS_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); + vmx_info->entry_ctrls.value = tmp_msr.lo; + { + struct vmx_exception_bitmap excp_bmap; + excp_bmap.value = 0; + + excp_bmap.pf = 1; + + vmx_ret |= check_vmcs_write(VMCS_EXCP_BITMAP, excp_bmap.value); + } /******* Setup VMXAssist guest state ***********/ info->rip = 0xd0000; @@ -493,6 +264,7 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config /* Print Control MSRs */ v3_get_msr(VMX_CR0_FIXED0_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); PrintDebug("CR0 MSR: %p\n", (void *)(addr_t)tmp_msr.value); + v3_get_msr(VMX_CR4_FIXED0_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); PrintDebug("CR4 MSR: %p\n", (void *)(addr_t)tmp_msr.value); @@ -501,143 +273,153 @@ static int init_vmx_guest(struct guest_info * info, struct v3_vm_config * config #define GUEST_CR4 0x00002000 info->ctrl_regs.cr0 = GUEST_CR0; info->ctrl_regs.cr4 = GUEST_CR4; + + ((struct cr0_32 *)&(info->shdw_pg_state.guest_cr0))->pe = 1; /* Setup paging */ - if(info->shdw_pg_mode == SHADOW_PAGING) { + if (info->shdw_pg_mode == SHADOW_PAGING) { PrintDebug("Creating initial shadow page table\n"); - if(v3_init_passthrough_pts(info) == -1) { + if (v3_init_passthrough_pts(info) == -1) { PrintError("Could not initialize passthrough page tables\n"); return -1; } + +#define CR0_PE 0x00000001 +#define CR0_PG 0x80000000 - info->shdw_pg_state.guest_cr0 = CR0_PE; - PrintDebug("Created\n"); vmx_ret |= check_vmcs_write(VMCS_CR0_MASK, (CR0_PE | CR0_PG) ); - vmx_ret |= check_vmcs_write(VMCS_CR0_READ_SHDW, info->shdw_pg_state.guest_cr0); vmx_ret |= check_vmcs_write(VMCS_CR4_MASK, CR4_VMXE); info->ctrl_regs.cr3 = info->direct_map_pt; - // vmx_data->pinbased_ctrls |= NMI_EXIT; + // vmx_info->pinbased_ctrls |= NMI_EXIT; /* Add CR exits */ - vmx_data->pri_procbased_ctrls |= CR3_LOAD_EXIT - | CR3_STORE_EXIT; - - vmx_data->exit_ctrls |= HOST_ADDR_SPACE_SIZE; + vmx_info->pri_proc_ctrls.cr3_ld_exit = 1; + vmx_info->pri_proc_ctrls.cr3_str_exit = 1; } - struct v3_segment * seg_reg = (struct v3_segment *)&(info->segments); - - int i; - for(i=0; i < 10; i++) + // Setup segment registers { - seg_reg[i].selector = 3<<3; - seg_reg[i].limit = 0xffff; - seg_reg[i].base = 0x0; - } - info->segments.cs.selector = 2<<3; - - /* Set only the segment registers */ - for(i=0; i < 6; i++) { - seg_reg[i].limit = 0xfffff; - seg_reg[i].granularity = 1; - seg_reg[i].type = 3; - seg_reg[i].system = 1; - seg_reg[i].dpl = 0; - seg_reg[i].present = 1; - seg_reg[i].db = 1; - } - info->segments.cs.type = 0xb; + struct v3_segment * seg_reg = (struct v3_segment *)&(info->segments); + + int i; + + for (i = 0; i < 10; i++) { + seg_reg[i].selector = 3 << 3; + seg_reg[i].limit = 0xffff; + seg_reg[i].base = 0x0; + } + + info->segments.cs.selector = 2<<3; + + /* Set only the segment registers */ + for (i = 0; i < 6; i++) { + seg_reg[i].limit = 0xfffff; + seg_reg[i].granularity = 1; + seg_reg[i].type = 3; + seg_reg[i].system = 1; + seg_reg[i].dpl = 0; + seg_reg[i].present = 1; + seg_reg[i].db = 1; + } + + info->segments.cs.type = 0xb; + + info->segments.ldtr.selector = 0x20; + info->segments.ldtr.type = 2; + info->segments.ldtr.system = 0; + info->segments.ldtr.present = 1; + info->segments.ldtr.granularity = 0; - info->segments.ldtr.selector = 0x20; - info->segments.ldtr.type = 2; - info->segments.ldtr.system = 0; - info->segments.ldtr.present = 1; - info->segments.ldtr.granularity = 0; - - /************* Map in GDT and vmxassist *************/ + /************* Map in GDT and vmxassist *************/ - uint64_t gdt[] __attribute__ ((aligned(32))) = { - 0x0000000000000000ULL, /* 0x00: reserved */ - 0x0000830000000000ULL, /* 0x08: 32-bit TSS */ - //0x0000890000000000ULL, /* 0x08: 32-bit TSS */ - 0x00CF9b000000FFFFULL, /* 0x10: CS 32-bit */ - 0x00CF93000000FFFFULL, /* 0x18: DS 32-bit */ - 0x000082000000FFFFULL, /* 0x20: LDTR 32-bit */ - }; + uint64_t gdt[] __attribute__ ((aligned(32))) = { + 0x0000000000000000ULL, /* 0x00: reserved */ + 0x0000830000000000ULL, /* 0x08: 32-bit TSS */ + //0x0000890000000000ULL, /* 0x08: 32-bit TSS */ + 0x00CF9b000000FFFFULL, /* 0x10: CS 32-bit */ + 0x00CF93000000FFFFULL, /* 0x18: DS 32-bit */ + 0x000082000000FFFFULL, /* 0x20: LDTR 32-bit */ + }; #define VMXASSIST_GDT 0x10000 - addr_t vmxassist_gdt = 0; - if(guest_pa_to_host_va(info, VMXASSIST_GDT, &vmxassist_gdt) == -1) { - PrintError("Could not find VMXASSIST GDT destination\n"); - return -1; - } - memcpy((void*)vmxassist_gdt, gdt, sizeof(uint64_t) * 5); + addr_t vmxassist_gdt = 0; + + if (guest_pa_to_host_va(info, VMXASSIST_GDT, &vmxassist_gdt) == -1) { + PrintError("Could not find VMXASSIST GDT destination\n"); + return -1; + } + + memcpy((void *)vmxassist_gdt, gdt, sizeof(uint64_t) * 5); - info->segments.gdtr.base = VMXASSIST_GDT; + info->segments.gdtr.base = VMXASSIST_GDT; #define VMXASSIST_TSS 0x40000 - uint64_t vmxassist_tss = VMXASSIST_TSS; - gdt[0x08 / sizeof(gdt[0])] |= - ((vmxassist_tss & 0xFF000000) << (56 - 24)) | - ((vmxassist_tss & 0x00FF0000) << (32 - 16)) | - ((vmxassist_tss & 0x0000FFFF) << (16)) | - (8392 - 1); - - info->segments.tr.selector = 0x08; - info->segments.tr.base = vmxassist_tss; - - //info->segments.tr.type = 0x9; - info->segments.tr.type = 0x3; - info->segments.tr.system = 0; - info->segments.tr.present = 1; - info->segments.tr.granularity = 0; - + uint64_t vmxassist_tss = VMXASSIST_TSS; + gdt[0x08 / sizeof(gdt[0])] |= + ((vmxassist_tss & 0xFF000000) << (56 - 24)) | + ((vmxassist_tss & 0x00FF0000) << (32 - 16)) | + ((vmxassist_tss & 0x0000FFFF) << (16)) | + (8392 - 1); + + info->segments.tr.selector = 0x08; + info->segments.tr.base = vmxassist_tss; + + //info->segments.tr.type = 0x9; + info->segments.tr.type = 0x3; + info->segments.tr.system = 0; + info->segments.tr.present = 1; + info->segments.tr.granularity = 0; + } + // setup VMXASSIST + { #define VMXASSIST_START 0x000d0000 - extern uint8_t v3_vmxassist_start[]; - extern uint8_t v3_vmxassist_end[]; + extern uint8_t v3_vmxassist_start[]; + extern uint8_t v3_vmxassist_end[]; + addr_t vmxassist_dst = 0; + + if (guest_pa_to_host_va(info, VMXASSIST_START, &vmxassist_dst) == -1) { + PrintError("Could not find VMXASSIST destination\n"); + return -1; + } + + memcpy((void *)vmxassist_dst, v3_vmxassist_start, v3_vmxassist_end - v3_vmxassist_start); + } - addr_t vmxassist_dst = 0; - if(guest_pa_to_host_va(info, VMXASSIST_START, &vmxassist_dst) == -1) { - PrintError("Could not find VMXASSIST destination\n"); - return -1; - } - memcpy((void*)vmxassist_dst, v3_vmxassist_start, v3_vmxassist_end - v3_vmxassist_start); - /*** Write all the info to the VMCS ***/ #define DEBUGCTL_MSR 0x1d9 v3_get_msr(DEBUGCTL_MSR, &(tmp_msr.hi), &(tmp_msr.lo)); vmx_ret |= check_vmcs_write(VMCS_GUEST_DBG_CTL, tmp_msr.value); - vmx_ret |= check_vmcs_write(VMCS_GUEST_DR7, 0x400); + info->dbg_regs.dr7 = 0x400; vmx_ret |= check_vmcs_write(VMCS_LINK_PTR, (addr_t)0xffffffffffffffffULL); - if(v3_update_vmcs_ctrl_fields(info)) { + if (v3_update_vmcs_ctrl_fields(info)) { PrintError("Could not write control fields!\n"); return -1; } - if(v3_update_vmcs_host_state(info)) { + if (v3_update_vmcs_host_state(info)) { PrintError("Could not write host state\n"); return -1; } - if(v3_update_vmcs_guest_state(info) != VMX_SUCCESS) { + if (v3_update_vmcs_guest_state(info) != VMX_SUCCESS) { PrintError("Writing guest state failed!\n"); return -1; } v3_print_vmcs(); - vmx_data->state = VMXASSIST_DISABLED; + vmx_info->state = VMXASSIST_DISABLED; v3_post_config_guest(info, config_ptr); @@ -651,15 +433,20 @@ static int start_vmx_guest(struct guest_info* info) { PrintDebug("Attempting VMLAUNCH\n"); - ret = v3_vmx_vmlaunch(&(info->vm_regs), info); + info->run_state = VM_RUNNING; + + rdtscll(info->time_state.cached_host_tsc); + + ret = v3_vmx_vmlaunch(&(info->vm_regs), info, &(info->ctrl_regs)); + if (ret != VMX_SUCCESS) { vmcs_read(VMCS_INSTR_ERR, &error); PrintError("VMLAUNCH failed: %d\n", error); v3_print_vmcs(); - } - PrintDebug("Returned from VMLAUNCH ret=%d(0x%x)\n", ret, ret); + + PrintDebug("Returned from VMLAUNCH ret=%d\n", ret); return -1; } @@ -699,9 +486,8 @@ static int has_vmx_nested_paging() { void v3_init_vmx(struct v3_ctrl_ops * vm_ops) { extern v3_cpu_arch_t v3_cpu_type; - struct v3_msr tmp_msr; - uint64_t ret=0; + uint64_t ret = 0; v3_get_msr(VMX_CR4_FIXED0_MSR,&(tmp_msr.hi),&(tmp_msr.lo)); @@ -714,7 +500,7 @@ void v3_init_vmx(struct v3_ctrl_ops * vm_ops) { : "%rbx" ); - if((~ret & tmp_msr.value) == 0) { + if ((~ret & tmp_msr.value) == 0) { __asm__ __volatile__ ( "movq %0, %%cr4;" : @@ -724,21 +510,23 @@ void v3_init_vmx(struct v3_ctrl_ops * vm_ops) { PrintError("Invalid CR4 Settings!\n"); return; } - __asm__ __volatile__ ( - "movq %%cr0, %%rbx; " - "orq $0x00000020,%%rbx; " - "movq %%rbx, %%cr0;" - : - : - : "%rbx" - ); - // + + __asm__ __volatile__ ( + "movq %%cr0, %%rbx; " + "orq $0x00000020,%%rbx; " + "movq %%rbx, %%cr0;" + : + : + : "%rbx" + ); + // // Should check and return Error here.... // Setup VMXON Region vmxon_ptr_phys = allocate_vmcs(); - PrintDebug("VMXON pointer: 0x%p\n", (void*)vmxon_ptr_phys); + + PrintDebug("VMXON pointer: 0x%p\n", (void *)vmxon_ptr_phys); if (v3_enable_vmx(vmxon_ptr_phys) == VMX_SUCCESS) { PrintDebug("VMX Enabled\n"); diff --git a/palacios/src/palacios/vmx_assist.c b/palacios/src/palacios/vmx_assist.c index 3e7933d..75f2774 100644 --- a/palacios/src/palacios/vmx_assist.c +++ b/palacios/src/palacios/vmx_assist.c @@ -29,51 +29,55 @@ int v3_vmxassist_ctx_switch(struct guest_info * info) { struct vmx_assist_context * old_ctx = NULL; struct vmx_assist_context * new_ctx = NULL; struct vmx_assist_header * hdr = NULL; - vmx_state_t state = ((struct vmx_data *)info->vmm_data)->state; + struct vmx_data * vmx_info = (struct vmx_data *)info->vmm_data; + if (guest_pa_to_host_va(info, VMXASSIST_BASE, (addr_t *)&hdr) == -1) { - PrintError("Could not translate address for vmxassist header\n"); - return -1; + PrintError("Could not translate address for vmxassist header\n"); + return -1; } if (hdr->magic != VMXASSIST_MAGIC) { - PrintError("VMXASSIT_MAGIC field is invalid\n"); + PrintError("VMXASSIST_MAGIC field is invalid\n"); return -1; } if (guest_pa_to_host_va(info, (addr_t)(hdr->old_ctx_gpa), (addr_t *)&(old_ctx)) == -1) { - PrintError("Could not translate address for VMXASSIST old context\n"); - return -1; + PrintError("Could not translate address for VMXASSIST old context\n"); + return -1; } if (guest_pa_to_host_va(info, (addr_t)(hdr->new_ctx_gpa), (addr_t *)&(new_ctx)) == -1) { - PrintError("Could not translate address for VMXASSIST new context\n"); - return -1; + PrintError("Could not translate address for VMXASSIST new context\n"); + return -1; } - - if (state == VMXASSIST_DISABLED) { - - /* Save the old Context */ + if (vmx_info->state == VMXASSIST_DISABLED) { + + /* Save the old Context */ if (vmx_save_world_ctx(info, old_ctx) != 0) { - PrintError("Could not save VMXASSIST world context\n"); + PrintError("Could not save VMXASSIST world context\n"); return -1; - } + } /* restore new context, vmxassist should launch the bios the first time */ if (vmx_restore_world_ctx(info, new_ctx) != 0) { - PrintError("VMXASSIST could not restore new context\n"); + PrintError("VMXASSIST could not restore new context\n"); return -1; - } + } - } else if (state == VMXASSIST_ENABLED) { + vmx_info->state = VMXASSIST_ENABLED; + + } else if (vmx_info->state == VMXASSIST_ENABLED) { /* restore old context */ if (vmx_restore_world_ctx(info, old_ctx) != 0) { - PrintError("VMXASSIST could not restore old context\n"); + PrintError("VMXASSIST could not restore old context\n"); return -1; - } + } + + vmx_info->state = VMXASSIST_DISABLED; } return 0; diff --git a/palacios/src/palacios/vmx_ctrl_regs.c b/palacios/src/palacios/vmx_ctrl_regs.c index 10503b4..8fb7a81 100644 --- a/palacios/src/palacios/vmx_ctrl_regs.c +++ b/palacios/src/palacios/vmx_ctrl_regs.c @@ -24,42 +24,266 @@ #include #include #include +#include +#include -static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t new_val); +static v3_reg_t * get_reg_ptr(struct guest_info * info, struct vmx_exit_cr_qual cr_qual); +static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t * new_val); +static int handle_mov_to_cr3(struct guest_info * info, v3_reg_t * cr3_reg); +static int handle_mov_from_cr3(struct guest_info * info, v3_reg_t * cr3_reg); -int v3_vmx_handle_cr0_write(struct guest_info * info, v3_reg_t new_val) { - return handle_mov_to_cr0(info, new_val); +int v3_vmx_handle_cr0_access(struct guest_info * info) { + struct vmx_exit_cr_qual cr_qual; + + vmcs_read(VMCS_EXIT_QUAL, &(cr_qual.value)); + + if (cr_qual.access_type < 2) { + v3_reg_t * reg = get_reg_ptr(info, cr_qual); + + if (cr_qual.access_type == 0) { + + if (handle_mov_to_cr0(info, reg) != 0) { + PrintError("Could not handle CR0 write\n"); + return -1; + } + } else { + // Mov from cr + PrintError("Mov From CR0 not handled\n"); + return -1; + } + + return 0; + } + + PrintError("Invalid CR0 Access type?? (type=%d)\n", cr_qual.access_type); + return -1; +} + +int v3_vmx_handle_cr3_access(struct guest_info * info) { + struct vmx_exit_cr_qual cr_qual; + + vmcs_read(VMCS_EXIT_QUAL, &(cr_qual.value)); + + if (cr_qual.access_type < 2) { + v3_reg_t * reg = get_reg_ptr(info, cr_qual); + + if (cr_qual.access_type == 0) { + return handle_mov_to_cr3(info, reg); + } else { + return handle_mov_from_cr3(info, reg); + } + } + + PrintError("Invalid CR3 Access type?? (type=%d)\n", cr_qual.access_type); + return -1; } -static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t new_val) { - PrintDebug("CR0 RIP: %p\n", (void *)info->rip); +static int handle_mov_to_cr3(struct guest_info * info, v3_reg_t * cr3_reg) { + int instr_len = 0; + + if (info->shdw_pg_mode == SHADOW_PAGING) { + + PrintDebug("Old Guest CR3=%p, Old Shadow CR3=%p\n", + (void *)info->ctrl_regs.cr3, + (void *)info->shdw_pg_state.guest_cr3); + + if (info->cpu_mode == LONG) { + info->shdw_pg_state.guest_cr3 = (uint64_t)*cr3_reg; + } else { + info->shdw_pg_state.guest_cr3 = (uint32_t)*cr3_reg; + } + + + if (v3_get_vm_mem_mode(info) == VIRTUAL_MEM) { + if (v3_activate_shadow_pt(info) == -1) { + PrintError("Failed to activate 32 bit shadow page table\n"); + return -1; + } + } + + PrintDebug("New guest CR3=%p, New shadow CR3=%p\n", + (void *)info->ctrl_regs.cr3, + (void *)info->shdw_pg_state.guest_cr3); + + } else if (info->shdw_pg_mode == NESTED_PAGING) { + PrintError("Nested paging not available in VMX right now!\n"); + return -1; + } + + + vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); + info->rip += instr_len; + + return 0; +} + +static int handle_mov_from_cr3(struct guest_info * info, v3_reg_t * cr3_reg) { + int instr_len = 0; + + if (info->shdw_pg_mode == SHADOW_PAGING) { + if ((v3_get_vm_cpu_mode(info) == LONG) || + (v3_get_vm_cpu_mode(info) == LONG_32_COMPAT)) { + + *cr3_reg = (uint64_t)info->shdw_pg_state.guest_cr3; + } else { + *cr3_reg = (uint32_t)info->shdw_pg_state.guest_cr3; + } + + } else { + PrintError("Unhandled paging mode\n"); + return -1; + } + + + vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); + info->rip += instr_len; + + return 0; +} + +static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t * new_cr0) { struct cr0_32 * guest_cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0); - struct cr0_32 * new_cr0 = (struct cr0_32 *)&new_val; - struct cr0_32 * shadow_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0); + struct cr0_32 * shdw_cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0); + struct cr0_32 * new_shdw_cr0 = (struct cr0_32 *)new_cr0; + struct vmx_data * vmx_info = (struct vmx_data *)info->vmm_data; + uint_t paging_transition = 0; + int instr_len = 0; - // PG and PE are always enabled for VMX + PrintDebug("Old shadow CR0: 0x%x, New shadow CR0: 0x%x\n", + (uint32_t)info->shdw_pg_state.guest_cr0, (uint32_t)*new_cr0); - // Check if this is a paging transition - PrintDebug("Old CR0: 0x%x\n", *(uint32_t *)guest_cr0); - PrintDebug("Old shadow CR0: 0x%x\n", *(uint32_t *)shadow_cr0); - PrintDebug("New CR0: 0x%x\n", *(uint32_t *)new_cr0); - - if ( new_cr0->pe ) { + + if (new_shdw_cr0->pe != shdw_cr0->pe) { + PrintDebug("Guest CR0: 0x%x\n", *(uint32_t *)guest_cr0); + PrintDebug("Old shadow CR0: 0x%x\n", *(uint32_t *)shdw_cr0); + PrintDebug("New shadow CR0: 0x%x\n", *(uint32_t *)new_shdw_cr0); if (v3_vmxassist_ctx_switch(info) != 0) { PrintError("Unable to execute VMXASSIST context switch!\n"); return -1; } - ((struct vmx_data *)info->vmm_data)->state = VMXASSIST_DISABLED; + v3_load_vmcs_guest_state(info); - PrintDebug("New Shadow: 0x%x\n", *(uint32_t *)shadow_cr0); - PrintDebug("mem_mode: %s\n", v3_mem_mode_to_str(v3_get_vm_mem_mode(info))); + if (vmx_info->state == VMXASSIST_ENABLED) { + PrintDebug("Loading VMXASSIST at RIP: %p\n", (void *)info->rip); + } else { + PrintDebug("Leaving VMXASSIST and entering protected mode at RIP: %p\n", + (void *)info->rip); + } + // vmx assist sets the new cr values itself return 0; } - return -1; + if (new_shdw_cr0->pg != shdw_cr0->pg) { + paging_transition = 1; + } + + // The shadow always reflects the new value + *shdw_cr0 = *new_shdw_cr0; + + // We don't care about most of the flags, so lets go for it + // and set them to the guest values + *guest_cr0 = *shdw_cr0; + + // Except PG, PE, and NE, which are always set + guest_cr0->pe = 1; + guest_cr0->pg = 1; + guest_cr0->ne = 1; + + if (paging_transition) { + // Paging transition + + if (v3_get_vm_mem_mode(info) == VIRTUAL_MEM) { + struct efer_64 * guest_efer = (struct efer_64 *)&(info->ctrl_regs.efer); + + if (guest_efer->lme == 1) { + PrintDebug("Enabling long mode\n"); + + guest_efer->lma = 1; + guest_efer->lme = 1; + + vmx_info->entry_ctrls.guest_ia32e = 1; + } + + PrintDebug("Activating Shadow Page tables\n"); + + if (v3_activate_shadow_pt(info) == -1) { + PrintError("Failed to activate shadow page tables\n"); + return -1; + } + + } else if (v3_activate_passthrough_pt(info) == -1) { + PrintError("Failed to activate passthrough page tables\n"); + return -1; + } + } + + // PE loads its own RIP, otherwise we need to skip ahead an instruction + + vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); + info->rip += instr_len; + + return 0; +} + +static v3_reg_t * get_reg_ptr(struct guest_info * info, struct vmx_exit_cr_qual cr_qual) { + v3_reg_t * reg = NULL; + + switch (cr_qual.gpr) { + case 0: + reg = &(info->vm_regs.rax); + break; + case 1: + reg = &(info->vm_regs.rcx); + break; + case 2: + reg = &(info->vm_regs.rdx); + break; + case 3: + reg = &(info->vm_regs.rbx); + break; + case 4: + reg = &(info->vm_regs.rsp); + break; + case 5: + reg = &(info->vm_regs.rbp); + break; + case 6: + reg = &(info->vm_regs.rsi); + break; + case 7: + reg = &(info->vm_regs.rdi); + break; + case 8: + reg = &(info->vm_regs.r8); + break; + case 9: + reg = &(info->vm_regs.r9); + break; + case 10: + reg = &(info->vm_regs.r10); + break; + case 11: + reg = &(info->vm_regs.r11); + break; + case 12: + reg = &(info->vm_regs.r11); + break; + case 13: + reg = &(info->vm_regs.r13); + break; + case 14: + reg = &(info->vm_regs.r14); + break; + case 15: + reg = &(info->vm_regs.r15); + break; + } + + return reg; } + diff --git a/palacios/src/palacios/vmx_handler.c b/palacios/src/palacios/vmx_handler.c index f872aee..af76455 100644 --- a/palacios/src/palacios/vmx_handler.c +++ b/palacios/src/palacios/vmx_handler.c @@ -28,11 +28,16 @@ #include #include #include +#include +#ifdef CONFIG_TELEMETRY +#include +#endif -static int inline check_vmcs_write(vmcs_field_t field, addr_t val) -{ + +static int inline check_vmcs_write(vmcs_field_t field, addr_t val) { int ret = 0; + ret = vmcs_write(field, val); if (ret != VMX_SUCCESS) { @@ -42,9 +47,9 @@ static int inline check_vmcs_write(vmcs_field_t field, addr_t val) return ret; } -static int inline check_vmcs_read(vmcs_field_t field, void * val) -{ +static int inline check_vmcs_read(vmcs_field_t field, void * val) { int ret = 0; + ret = vmcs_read(field, val); if (ret != VMX_SUCCESS) { @@ -54,351 +59,336 @@ static int inline check_vmcs_read(vmcs_field_t field, void * val) return ret; } -static void inline translate_access_to_v3_seg(struct vmcs_segment_access * access, - struct v3_segment * v3_seg) { - v3_seg->type = access->type; - v3_seg->system = access->desc_type; - v3_seg->dpl = access->dpl; - v3_seg->present = access->present; - v3_seg->avail = access->avail; - v3_seg->long_mode = access->long_mode; - v3_seg->db = access->db; - v3_seg->granularity = access->granularity; +static int inline handle_cr_access(struct guest_info * info, ulong_t exit_qual) { + struct vmx_exit_cr_qual * cr_qual = (struct vmx_exit_cr_qual *)&exit_qual; + + // PrintDebug("Control register: %d\n", cr_qual->access_type); + switch(cr_qual->cr_id) { + case 0: + PrintDebug("Handling CR0 Access\n"); + return v3_vmx_handle_cr0_access(info); + case 3: + PrintDebug("Handling CR3 Access\n"); + return v3_vmx_handle_cr3_access(info); + default: + PrintError("Unhandled CR access: %d\n", cr_qual->cr_id); + return -1; + } + + return -1; } -static int load_vmcs_guest_state(struct guest_info * info) -{ - - struct vmcs_segment_access access; - int ret = 0; - - // JRL: Add error checking - memset(&access, 0, sizeof(access)); - - /* CS Segment */ - check_vmcs_read(VMCS_GUEST_CS_BASE, &(info->segments.cs.base)); - check_vmcs_read(VMCS_GUEST_CS_SELECTOR, &(info->segments.cs.selector)); - check_vmcs_read(VMCS_GUEST_CS_LIMIT, &(info->segments.cs.limit)); - check_vmcs_read(VMCS_GUEST_CS_ACCESS, &(access.value)); +/* At this point the GPRs are already copied into the guest_info state */ +int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info, struct v3_ctrl_regs * ctrl_regs) { + uint64_t tmp_tsc = 0; + uint32_t exit_reason = 0; + addr_t exit_qual = 0; + struct vmx_data * vmx_info = (struct vmx_data *)(info->vmm_data); + struct vmx_exit_idt_vec_info idt_vec_info; - translate_access_to_v3_seg(&access, &(info->segments.cs)); + rdtscll(tmp_tsc); + v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc); - /* SS Segment */ - check_vmcs_read(VMCS_GUEST_SS_BASE, &(info->segments.ss.base)); - check_vmcs_read(VMCS_GUEST_SS_SELECTOR, &(info->segments.ss.selector)); - check_vmcs_read(VMCS_GUEST_SS_LIMIT, &(info->segments.ss.limit)); - check_vmcs_read(VMCS_GUEST_SS_ACCESS, &(access.value)); + v3_enable_ints(); - translate_access_to_v3_seg(&access, &(info->segments.ss)); + check_vmcs_read(VMCS_EXIT_REASON, &exit_reason); + check_vmcs_read(VMCS_EXIT_QUAL, &exit_qual); - /* DS Segment */ - check_vmcs_read(VMCS_GUEST_DS_BASE, &(info->segments.ds.base)); - check_vmcs_read(VMCS_GUEST_DS_SELECTOR, &(info->segments.ds.selector)); - check_vmcs_read(VMCS_GUEST_DS_LIMIT, &(info->segments.ds.limit)); - check_vmcs_read(VMCS_GUEST_DS_ACCESS, &(access.value)); + //PrintDebug("VMX Exit taken, id-qual: %u-%lu\n", exit_reason, exit_qual); - translate_access_to_v3_seg(&access, &(info->segments.ds)); + /* Update guest state */ + v3_load_vmcs_guest_state(info); - /* ES Segment */ - check_vmcs_read(VMCS_GUEST_ES_BASE, &(info->segments.es.base)); - check_vmcs_read(VMCS_GUEST_ES_SELECTOR, &(info->segments.es.selector)); - check_vmcs_read(VMCS_GUEST_ES_LIMIT, &(info->segments.es.limit)); - check_vmcs_read(VMCS_GUEST_ES_ACCESS, &(access.value)); + // Load execution controls + check_vmcs_read(VMCS_PIN_CTRLS, &(vmx_info->pin_ctrls.value)); + check_vmcs_read(VMCS_PROC_CTRLS, &(vmx_info->pri_proc_ctrls.value)); - translate_access_to_v3_seg(&access, &(info->segments.es)); + if (vmx_info->pri_proc_ctrls.sec_ctrls) { + check_vmcs_read(VMCS_SEC_PROC_CTRLS, &(vmx_info->sec_proc_ctrls.value)); + } - /* FS Segment */ - check_vmcs_read(VMCS_GUEST_FS_BASE, &(info->segments.fs.base)); - check_vmcs_read(VMCS_GUEST_FS_SELECTOR, &(info->segments.fs.selector)); - check_vmcs_read(VMCS_GUEST_FS_LIMIT, &(info->segments.fs.limit)); - check_vmcs_read(VMCS_GUEST_FS_ACCESS, &(access.value)); + info->mem_mode = v3_get_vm_mem_mode(info); + info->cpu_mode = v3_get_vm_cpu_mode(info); - translate_access_to_v3_seg(&access, &(info->segments.fs)); + // Check if we got interrupted while delivering interrupt + // Variable will be used later if this is true + check_vmcs_read(VMCS_IDT_VECTOR_INFO, &(idt_vec_info.value)); - /* GS Segment */ - check_vmcs_read(VMCS_GUEST_GS_BASE, &(info->segments.gs.base)); - check_vmcs_read(VMCS_GUEST_GS_SELECTOR, &(info->segments.gs.selector)); - check_vmcs_read(VMCS_GUEST_GS_LIMIT, &(info->segments.gs.limit)); - check_vmcs_read(VMCS_GUEST_GS_ACCESS, &(access.value)); + if ((info->intr_state.irq_started == 1) && (idt_vec_info.valid == 0)) { +#ifdef CONFIG_DEBUG_INTERRUPTS + PrintDebug("Calling v3_injecting_intr\n"); +#endif + info->intr_state.irq_started = 0; + v3_injecting_intr(info, info->intr_state.irq_vector, V3_EXTERNAL_IRQ); + } - translate_access_to_v3_seg(&access, &(info->segments.gs)); + info->num_exits++; - /* LDTR Segment */ - check_vmcs_read(VMCS_GUEST_LDTR_BASE, &(info->segments.ldtr.base)); - check_vmcs_read(VMCS_GUEST_LDTR_SELECTOR, &(info->segments.ldtr.selector)); - check_vmcs_read(VMCS_GUEST_LDTR_LIMIT, &(info->segments.ldtr.limit)); - check_vmcs_read(VMCS_GUEST_LDTR_ACCESS, &(access.value)); - translate_access_to_v3_seg(&access, &(info->segments.ldtr)); - /* TR Segment */ - check_vmcs_read(VMCS_GUEST_TR_BASE, &(info->segments.tr.base)); - check_vmcs_read(VMCS_GUEST_TR_SELECTOR, &(info->segments.tr.selector)); - check_vmcs_read(VMCS_GUEST_TR_LIMIT, &(info->segments.tr.limit)); - check_vmcs_read(VMCS_GUEST_TR_ACCESS, &(access.value)); + if ((info->num_exits % 5000) == 0) { + PrintDebug("VMX Exit %d\n", (uint32_t)info->num_exits); + } - translate_access_to_v3_seg(&access, &(info->segments.tr)); +#ifdef CONFIG_TELEMETRY + if (info->enable_telemetry) { + v3_telemetry_start_exit(info); + } +#endif - /* GDTR Segment */ - check_vmcs_read(VMCS_GUEST_GDTR_BASE, &(info->segments.gdtr.base)); - check_vmcs_read(VMCS_GUEST_GDTR_LIMIT, &(info->segments.gdtr.limit)); - - /* IDTR Segment */ - check_vmcs_read(VMCS_GUEST_IDTR_BASE, &(info->segments.idtr.base)); - check_vmcs_read(VMCS_GUEST_IDTR_LIMIT, &(info->segments.idtr.limit)); + switch (exit_reason) { + case VMEXIT_INFO_EXCEPTION_OR_NMI: { + uint32_t int_info; + pf_error_t error_code; + check_vmcs_read(VMCS_EXIT_INT_INFO, &int_info); + check_vmcs_read(VMCS_EXIT_INT_ERR, &error_code); - /* - * Read the control state - */ - check_vmcs_read(VMCS_GUEST_RIP, &(info->rip)); - check_vmcs_read(VMCS_GUEST_RSP, &(info->vm_regs.rsp)); - check_vmcs_read(VMCS_GUEST_CR0, &(info->ctrl_regs.cr0)); - check_vmcs_read(VMCS_CR0_READ_SHDW, &(info->shdw_pg_state.guest_cr0)); - check_vmcs_read(VMCS_GUEST_CR3, &(info->ctrl_regs.cr3)); - check_vmcs_read(VMCS_GUEST_CR4, &(info->ctrl_regs.cr4)); + // JRL: Change "0x0e" to a macro value + if ((uint8_t)int_info == 0x0e) { +#ifdef CONFIG_DEBUG_SHADOW_PAGING + PrintDebug("Page Fault at %p error_code=%x\n", (void *)exit_qual, *(uint32_t *)&error_code); +#endif - return ret; -} + if (info->shdw_pg_mode == SHADOW_PAGING) { + if (v3_handle_shadow_pagefault(info, (addr_t)exit_qual, error_code) == -1) { + PrintError("Error handling shadow page fault\n"); + return -1; + } + } else { + PrintError("Page fault in unimplemented paging mode\n"); + return -1; + } + } else { + PrintError("Unknown exception: 0x%x\n", (uint8_t)int_info); + v3_print_GPRs(info); + return -1; + } + break; + } + case VMEXIT_INVLPG: + if (info->shdw_pg_mode == SHADOW_PAGING) { + if (v3_handle_shadow_invlpg(info) == -1) { + PrintError("Error handling INVLPG\n"); + return -1; + } + } -#if 0 -static void setup_v8086_mode_for_boot(struct guest_info * info) -{ + break; + case VMEXIT_CPUID: { + int instr_len; + uint32_t target = info->vm_regs.rax; - ((struct vmx_data *)info->vmm_data)->state = VMXASSIST_V8086_BIOS; - struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags); - flags->rsvd1 = 1; - flags->vm = 1; - flags->iopl = 3; + v3_cpuid(target, (addr_t *)&(info->vm_regs.rax), (addr_t *)&(info->vm_regs.rbx), + (addr_t *)&(info->vm_regs.rcx), (addr_t *)&(info->vm_regs.rdx)); - info->rip = 0xfff0; - - /* Zero the segment registers */ - memset(&(info->segments), 0, sizeof(struct v3_segment)*6); + check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); + info->rip += instr_len; - info->segments.cs.selector = 0xf000; - info->segments.cs.base = 0xf000 << 4; - info->segments.cs.limit = 0xffff; - info->segments.cs.type = 3; - info->segments.cs.system = 1; - info->segments.cs.dpl = 3; - info->segments.cs.present = 1; - info->segments.cs.granularity = 0; + break; + } + case VMEXIT_RDMSR: + if (v3_handle_msr_read(info) == -1) { + PrintError("Error handling MSR Read\n"); + return -1; + } - int i; - - /* Set values for selectors ds through ss */ - struct v3_segment * seg_ptr = (struct v3_segment *)&(info->segments); - for(i = 1; i < 6 ; i++) { - seg_ptr[i].selector = 0x0000; - seg_ptr[i].base = 0x00000; - seg_ptr[i].limit = 0xffff; - seg_ptr[i].type = 3; - seg_ptr[i].system = 1; - seg_ptr[i].dpl = 3; - seg_ptr[i].present = 1; - seg_ptr[i].granularity = 0; - } + break; + case VMEXIT_WRMSR: + if (v3_handle_msr_write(info) == -1) { + PrintError("Error handling MSR Write\n"); + return -1; + } -} + break; + case VMEXIT_IO_INSTR: { + struct vmx_exit_io_qual * io_qual = (struct vmx_exit_io_qual *)&exit_qual; + + if (io_qual->dir == 0) { + if (io_qual->string) { + if (v3_handle_vmx_io_outs(info) == -1) { + PrintError("Error in outs IO handler\n"); + return -1; + } + } else { + if (v3_handle_vmx_io_out(info) == -1) { + PrintError("Error in out IO handler\n"); + return -1; + } + } + } else { + if (io_qual->string) { + if(v3_handle_vmx_io_ins(info) == -1) { + PrintError("Error in ins IO handler\n"); + return -1; + } + } else { + if (v3_handle_vmx_io_in(info) == -1) { + PrintError("Error in in IO handler\n"); + return -1; + } + } + } + break; + } + case VMEXIT_CR_REG_ACCESSES: + if (handle_cr_access(info, exit_qual) != 0) { + PrintError("Error handling CR access\n"); + return -1; + } -#endif - -static int inline handle_cr_access(struct guest_info * info, ulong_t exit_qual) { - struct vmexit_cr_qual * cr_qual = (struct vmexit_cr_qual *)&exit_qual; + break; + case VMEXIT_HLT: + PrintDebug("Guest halted\n"); - PrintDebug("Control register: %d\n", cr_qual->access_type); + if (v3_handle_halt(info) == -1) { + PrintError("Error handling halt instruction\n"); + return -1; + } - if (cr_qual->access_type < 2) { - v3_reg_t reg = 0; - - switch(cr_qual->gpr) { - case 0: - reg = info->vm_regs.rax; - break; - case 1: - reg = info->vm_regs.rcx; - break; - case 2: - reg = info->vm_regs.rdx; - break; - case 3: - reg = info->vm_regs.rbx; - break; - case 4: - reg = info->vm_regs.rsp; - break; - case 5: - reg = info->vm_regs.rbp; - break; - case 6: - reg = info->vm_regs.rsi; - break; - case 7: - reg = info->vm_regs.rdi; - break; - case 8: - reg = info->vm_regs.r8; - break; - case 9: - reg = info->vm_regs.r9; - break; - case 10: - reg = info->vm_regs.r10; - break; - case 11: - reg = info->vm_regs.r11; - break; - case 12: - reg = info->vm_regs.r11; - break; - case 13: - reg = info->vm_regs.r13; - break; - case 14: - reg = info->vm_regs.r14; - break; - case 15: - reg = info->vm_regs.r15; - break; - } + break; + case VMEXIT_PAUSE: + // Handled as NOP + info->rip += 2; - if (cr_qual->cr_id == 0) { - uint32_t instr_len; + break; + case VMEXIT_EXTERNAL_INTR: + // Interrupts are handled outside switch + break; + case VMEXIT_INTR_WINDOW: - vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); + vmx_info->pri_proc_ctrls.int_wndw_exit = 0; + check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value); - if ( ~reg & CR0_PE ) { +#ifdef CONFIG_DEBUG_INTERRUPTS + PrintDebug("Interrupts available again! (RIP=%llx)\n", info->rip); +#endif - if (v3_vmxassist_ctx_switch(info) != 0) { - PrintError("Unable to execute VMXASSIST context switch!\n"); - return -1; - } + break; + default: + PrintError("Unhandled VMEXIT: %s (%u), %lu (0x%lx)\n", + v3_vmx_exit_code_to_str(exit_reason), + exit_reason, exit_qual, exit_qual); + return -1; + } - load_vmcs_guest_state(info); +#ifdef CONFIG_TELEMETRY + if (info->enable_telemetry) { + v3_telemetry_end_exit(info, exit_reason); + } +#endif - ((struct vmx_data *)info->vmm_data)->state = VMXASSIST_ENABLED; - PrintDebug("Loading vmxassist at RIP: 0x%p\n", (void *)info->rip); - return 0; - } else if (v3_vmx_handle_cr0_write(info, reg) != 0) { - PrintError("Could not handle CR0 Write\n"); - return -1; - } + /* Check for pending exceptions to inject */ + if (v3_excp_pending(info)) { + struct vmx_entry_int_info int_info; + int_info.value = 0; - load_vmcs_guest_state(info); + // In VMX, almost every exception is hardware + // Software exceptions are pretty much only for breakpoint or overflow + int_info.type = 3; + int_info.vector = v3_get_excp_number(info); - PrintDebug("Leaving VMXASSIST and entering protected mode at RIP: 0x%p\n", (void *)info->rip); + if (info->excp_state.excp_error_code_valid) { + check_vmcs_write(VMCS_ENTRY_EXCP_ERR, info->excp_state.excp_error_code); + int_info.error_code = 1; - return 0; + PrintDebug("Injecting exception %d with error code %x\n", + int_info.vector, info->excp_state.excp_error_code); } - } - PrintError("Unhandled CR access\n"); - return -1; -} + int_info.valid = 1; + PrintDebug("Injecting exception %d (EIP=%p)\n", int_info.vector, (void *)info->rip); + check_vmcs_write(VMCS_ENTRY_INT_INFO, int_info.value); + v3_injecting_excp(info, int_info.vector); -/* At this point the GPRs are already copied into the guest_info state */ -int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info) { - uint32_t exit_reason; - ulong_t exit_qual; + } else if (((struct rflags *)&(info->ctrl_regs.rflags))->intr == 1) { + + if ((info->intr_state.irq_started == 1) && (idt_vec_info.valid == 1)) { - check_vmcs_read(VMCS_EXIT_REASON, &exit_reason); - check_vmcs_read(VMCS_EXIT_QUAL, &exit_qual); +#ifdef CONFIG_DEBUG_INTERRUPTS + PrintDebug("IRQ pending from previous injection\n"); +#endif - // PrintDebug("VMX Exit taken, id-qual: %u-%lu\n", exit_reason, exit_qual); + // Copy the IDT vectoring info over to reinject the old interrupt + if (idt_vec_info.error_code == 1) { + uint32_t err_code = 0; - /* Update guest state */ - load_vmcs_guest_state(info); - - switch (exit_reason) { - case VMEXIT_INFO_EXCEPTION_OR_NMI: { - uint32_t int_info; - pf_error_t error_code; - - check_vmcs_read(VMCS_EXIT_INT_INFO, &int_info); - check_vmcs_read(VMCS_EXIT_INT_ERR, &error_code); - - // JRL: Change "0x0e" to a macro value - if ((uint8_t)int_info == 0x0e) { - PrintDebug("Page Fault at %p\n", (void *)exit_qual); - - if (info->shdw_pg_mode == SHADOW_PAGING) { - if (v3_handle_shadow_pagefault(info, (addr_t)exit_qual, error_code) == -1) { - PrintError("Error handling shadow page fault\n"); - return -1; - } - } else { - PrintError("Page fault in unimplemented paging mode\n"); - return -1; - } - } else { - PrintDebug("Unknown exception: 0x%x\n", (uint8_t)int_info); - v3_print_GPRs(info); - return -1; - } - break; - } - - case VMEXIT_CPUID: { - int instr_len; + check_vmcs_read(VMCS_IDT_VECTOR_ERR, &err_code); + check_vmcs_write(VMCS_ENTRY_EXCP_ERR, err_code); + } - v3_cpuid(info->vm_regs.rax, (addr_t *)&(info->vm_regs.rax), (addr_t *)&(info->vm_regs.rbx), - (addr_t *)&(info->vm_regs.rcx), (addr_t *)&(info->vm_regs.rdx)); + idt_vec_info.undef = 0; + check_vmcs_write(VMCS_ENTRY_INT_INFO, idt_vec_info.value); + + } else { + struct vmx_entry_int_info ent_int; + ent_int.value = 0; + + switch (v3_intr_pending(info)) { + case V3_EXTERNAL_IRQ: { + info->intr_state.irq_vector = v3_get_intr(info); + ent_int.vector = info->intr_state.irq_vector; + ent_int.type = 0; + ent_int.error_code = 0; + ent_int.valid = 1; + +#ifdef CONFIG_DEBUG_INTERRUPTS + PrintDebug("Injecting Interrupt %d at exit %u(EIP=%p)\n", + info->intr_state.irq_vector, + (uint32_t)info->num_exits, + (void *)info->rip); +#endif - check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); + check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value); + info->intr_state.irq_started = 1; - info->rip += instr_len; - break; - } - - case VMEXIT_IO_INSTR: { - struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual; - - if (io_qual->dir == 0) { - if (io_qual->string) { - if (v3_handle_vmx_io_outs(info) == -1) { - PrintError("Error in outs IO handler\n"); - return -1; - } - } else { - if (v3_handle_vmx_io_out(info) == -1) { - PrintError("Error in out IO handler\n"); - return -1; - } - } - } else { - if (io_qual->string) { - if(v3_handle_vmx_io_ins(info) == -1) { - PrintError("Error in ins IO handler\n"); - return -1; - } - } else { - if (v3_handle_vmx_io_in(info) == -1) { - PrintError("Error in in IO handler\n"); - return -1; - } - } - } - break; - } - - case VMEXIT_CR_REG_ACCESSES: - if (handle_cr_access(info,exit_qual) != 0) { - PrintError("Error handling CR access\n"); - return -1; - } + break; + } + case V3_NMI: + PrintDebug("Injecting NMI\n"); + + ent_int.type = 2; + ent_int.vector = 2; + ent_int.valid = 1; + check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value); + + break; + case V3_SOFTWARE_INTR: + PrintDebug("Injecting software interrupt\n"); + ent_int.type = 4; + + ent_int.valid = 1; + check_vmcs_write(VMCS_ENTRY_INT_INFO, ent_int.value); + + break; + case V3_VIRTUAL_IRQ: + // Not sure what to do here, Intel doesn't have virtual IRQs + // May be the same as external interrupts/IRQs + + break; + case V3_INVALID_INTR: + default: + break; + } + } + } else if ((v3_intr_pending(info)) && (vmx_info->pri_proc_ctrls.int_wndw_exit == 0)) { + // Enable INTR window exiting so we know when IF=1 + uint32_t instr_len; - break; + check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); - default: - PrintError("Unhandled VMEXIT: %u (0x%x), %lu (0x%lx)\n", exit_reason, exit_reason, exit_qual, exit_qual); - return -1; +#ifdef CONFIG_DEBUG_INTERRUPTS + PrintDebug("Enabling Interrupt-Window exiting: %d\n", instr_len); +#endif + + vmx_info->pri_proc_ctrls.int_wndw_exit = 1; + check_vmcs_write(VMCS_PROC_CTRLS, vmx_info->pri_proc_ctrls.value); } check_vmcs_write(VMCS_GUEST_CR0, info->ctrl_regs.cr0); @@ -409,5 +399,168 @@ int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info) { check_vmcs_write(VMCS_CR0_READ_SHDW, info->shdw_pg_state.guest_cr0); + v3_disable_ints(); + + rdtscll(info->time_state.cached_host_tsc); + return 0; } + +static const char VMEXIT_INFO_EXCEPTION_OR_NMI_STR[] = "VMEXIT_INFO_EXCEPTION_OR_NMI"; +static const char VMEXIT_EXTERNAL_INTR_STR[] = "VMEXIT_EXTERNAL_INTR"; +static const char VMEXIT_TRIPLE_FAULT_STR[] = "VMEXIT_TRIPLE_FAULT"; +static const char VMEXIT_INIT_SIGNAL_STR[] = "VMEXIT_INIT_SIGNAL"; +static const char VMEXIT_STARTUP_IPI_STR[] = "VMEXIT_STARTUP_IPI"; +static const char VMEXIT_IO_SMI_STR[] = "VMEXIT_IO_SMI"; +static const char VMEXIT_OTHER_SMI_STR[] = "VMEXIT_OTHER_SMI"; +static const char VMEXIT_INTR_WINDOW_STR[] = "VMEXIT_INTR_WINDOW"; +static const char VMEXIT_NMI_WINDOW_STR[] = "VMEXIT_NMI_WINDOW"; +static const char VMEXIT_TASK_SWITCH_STR[] = "VMEXIT_TASK_SWITCH"; +static const char VMEXIT_CPUID_STR[] = "VMEXIT_CPUID"; +static const char VMEXIT_HLT_STR[] = "VMEXIT_HLT"; +static const char VMEXIT_INVD_STR[] = "VMEXIT_INVD"; +static const char VMEXIT_INVLPG_STR[] = "VMEXIT_INVLPG"; +static const char VMEXIT_RDPMC_STR[] = "VMEXIT_RDPMC"; +static const char VMEXIT_RDTSC_STR[] = "VMEXIT_RDTSC"; +static const char VMEXIT_RSM_STR[] = "VMEXIT_RSM"; +static const char VMEXIT_VMCALL_STR[] = "VMEXIT_VMCALL"; +static const char VMEXIT_VMCLEAR_STR[] = "VMEXIT_VMCLEAR"; +static const char VMEXIT_VMLAUNCH_STR[] = "VMEXIT_VMLAUNCH"; +static const char VMEXIT_VMPTRLD_STR[] = "VMEXIT_VMPTRLD"; +static const char VMEXIT_VMPTRST_STR[] = "VMEXIT_VMPTRST"; +static const char VMEXIT_VMREAD_STR[] = "VMEXIT_VMREAD"; +static const char VMEXIT_VMRESUME_STR[] = "VMEXIT_VMRESUME"; +static const char VMEXIT_VMWRITE_STR[] = "VMEXIT_VMWRITE"; +static const char VMEXIT_VMXOFF_STR[] = "VMEXIT_VMXOFF"; +static const char VMEXIT_VMXON_STR[] = "VMEXIT_VMXON"; +static const char VMEXIT_CR_REG_ACCESSES_STR[] = "VMEXIT_CR_REG_ACCESSES"; +static const char VMEXIT_MOV_DR_STR[] = "VMEXIT_MOV_DR"; +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_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_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"; +static const char VMEXIT_LDTR_TR_STR[] = "VMEXIT_LDTR_TR"; +static const char VMEXIT_EPT_VIOLATION_STR[] = "VMEXIT_EPT_VIOLATION"; +static const char VMEXIT_EPT_CONFIG_STR[] = "VMEXIT_EPT_CONFIG"; +static const char VMEXIT_INVEPT_STR[] = "VMEXIT_INVEPT"; +static const char VMEXIT_RDTSCP_STR[] = "VMEXIT_RDTSCP"; +static const char VMEXIT_EXPIRED_PREEMPT_TIMER_STR[] = "VMEXIT_EXPIRED_PREEMPT_TIMER"; +static const char VMEXIT_INVVPID_STR[] = "VMEXIT_INVVPID"; +static const char VMEXIT_WBINVD_STR[] = "VMEXIT_WBINVD"; +static const char VMEXIT_XSETBV_STR[] = "VMEXIT_XSETBV"; + +const char * v3_vmx_exit_code_to_str(vmx_exit_t exit) +{ + switch(exit) { + case VMEXIT_INFO_EXCEPTION_OR_NMI: + return VMEXIT_INFO_EXCEPTION_OR_NMI_STR; + case VMEXIT_EXTERNAL_INTR: + return VMEXIT_EXTERNAL_INTR_STR; + case VMEXIT_TRIPLE_FAULT: + return VMEXIT_TRIPLE_FAULT_STR; + case VMEXIT_INIT_SIGNAL: + return VMEXIT_INIT_SIGNAL_STR; + case VMEXIT_STARTUP_IPI: + return VMEXIT_STARTUP_IPI_STR; + case VMEXIT_IO_SMI: + return VMEXIT_IO_SMI_STR; + case VMEXIT_OTHER_SMI: + return VMEXIT_OTHER_SMI_STR; + case VMEXIT_INTR_WINDOW: + return VMEXIT_INTR_WINDOW_STR; + case VMEXIT_NMI_WINDOW: + return VMEXIT_NMI_WINDOW_STR; + case VMEXIT_TASK_SWITCH: + return VMEXIT_TASK_SWITCH_STR; + case VMEXIT_CPUID: + return VMEXIT_CPUID_STR; + case VMEXIT_HLT: + return VMEXIT_HLT_STR; + case VMEXIT_INVD: + return VMEXIT_INVD_STR; + case VMEXIT_INVLPG: + return VMEXIT_INVLPG_STR; + case VMEXIT_RDPMC: + return VMEXIT_RDPMC_STR; + case VMEXIT_RDTSC: + return VMEXIT_RDTSC_STR; + case VMEXIT_RSM: + return VMEXIT_RSM_STR; + case VMEXIT_VMCALL: + return VMEXIT_VMCALL_STR; + case VMEXIT_VMCLEAR: + return VMEXIT_VMCLEAR_STR; + case VMEXIT_VMLAUNCH: + return VMEXIT_VMLAUNCH_STR; + case VMEXIT_VMPTRLD: + return VMEXIT_VMPTRLD_STR; + case VMEXIT_VMPTRST: + return VMEXIT_VMPTRST_STR; + case VMEXIT_VMREAD: + return VMEXIT_VMREAD_STR; + case VMEXIT_VMRESUME: + return VMEXIT_VMRESUME_STR; + case VMEXIT_VMWRITE: + return VMEXIT_VMWRITE_STR; + case VMEXIT_VMXOFF: + return VMEXIT_VMXOFF_STR; + case VMEXIT_VMXON: + return VMEXIT_VMXON_STR; + case VMEXIT_CR_REG_ACCESSES: + return VMEXIT_CR_REG_ACCESSES_STR; + case VMEXIT_MOV_DR: + return VMEXIT_MOV_DR_STR; + case VMEXIT_IO_INSTR: + return VMEXIT_IO_INSTR_STR; + case VMEXIT_RDMSR: + 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_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_TPR_BELOW_THRESHOLD: + return VMEXIT_TPR_BELOW_THRESHOLD_STR; + case VMEXIT_APIC: + return VMEXIT_APIC_STR; + case VMEXIT_GDTR_IDTR: + return VMEXIT_GDTR_IDTR_STR; + case VMEXIT_LDTR_TR: + return VMEXIT_LDTR_TR_STR; + case VMEXIT_EPT_VIOLATION: + return VMEXIT_EPT_VIOLATION_STR; + case VMEXIT_EPT_CONFIG: + return VMEXIT_EPT_CONFIG_STR; + case VMEXIT_INVEPT: + return VMEXIT_INVEPT_STR; + case VMEXIT_RDTSCP: + return VMEXIT_RDTSCP_STR; + case VMEXIT_EXPIRED_PREEMPT_TIMER: + return VMEXIT_EXPIRED_PREEMPT_TIMER_STR; + case VMEXIT_INVVPID: + return VMEXIT_INVVPID_STR; + case VMEXIT_WBINVD: + return VMEXIT_WBINVD_STR; + case VMEXIT_XSETBV: + return VMEXIT_XSETBV_STR; + } + return NULL; +} + diff --git a/palacios/src/palacios/vmx_io.c b/palacios/src/palacios/vmx_io.c index 0f841e4..8554606 100644 --- a/palacios/src/palacios/vmx_io.c +++ b/palacios/src/palacios/vmx_io.c @@ -34,8 +34,7 @@ /* Same as SVM */ -static int update_map(struct guest_info * info, uint16_t port, int hook_read, int hook_write) -{ +static int update_map(struct guest_info * info, uint16_t port, int hook_read, int hook_write) { uchar_t * bitmap = (uint8_t *)(info->io_map.arch_data); int major = port / 8; int minor = port % 8; @@ -49,43 +48,39 @@ static int update_map(struct guest_info * info, uint16_t port, int hook_read, in return 0; } -int v3_init_vmx_io_map(struct guest_info * info) -{ +int v3_init_vmx_io_map(struct guest_info * info) { info->io_map.update_map = update_map; info->io_map.arch_data = V3_VAddr(V3_AllocPages(2)); - memset(info->io_map.arch_data, 0, PAGE_SIZE_4KB*2); + memset(info->io_map.arch_data, 0, PAGE_SIZE_4KB * 2); return 0; } int v3_handle_vmx_io_in(struct guest_info * info) { - ulong_t exit_qual; + struct vmx_exit_io_qual io_qual; + struct v3_io_hook * hook = NULL; + int read_size = 0; uint32_t instr_length = 0; - vmcs_read(VMCS_EXIT_QUAL, &exit_qual); - - struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual; - - struct v3_io_hook * hook = v3_get_io_hook(info, io_qual->port); - int read_size = 0; + io_qual.value = 0; + vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value)); + hook = v3_get_io_hook(info, io_qual.port); if (hook == NULL) { - PrintError("Hook not present for IN on port %x\n", io_qual->port); + PrintError("Hook not present for IN on port %x\n", io_qual.port); return -1; } - read_size = io_qual->access_size + 1; + read_size = io_qual.access_size + 1; - PrintDebug("IN of %d bytes on port %d (0x%x)\n", read_size, io_qual->port, io_qual->port); + PrintDebug("IN of %d bytes on port %d (0x%x)\n", read_size, io_qual.port, io_qual.port); - if (hook->read(io_qual->port, &(info->vm_regs.rax), read_size, hook->priv_data) != read_size) { - PrintError("Read failure for IN on port %x\n", io_qual->port); + if (hook->read(io_qual.port, &(info->vm_regs.rax), read_size, hook->priv_data) != read_size) { + PrintError("Read failure for IN on port %x\n", io_qual.port); return -1; } - - if (vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_length) != VMX_SUCCESS) { PrintError("Could not read instruction length\n"); return -1; @@ -96,34 +91,49 @@ int v3_handle_vmx_io_in(struct guest_info * info) { return 0; } -int v3_handle_vmx_io_ins(struct guest_info * info) -{ - ulong_t exit_qual; - - vmcs_read(VMCS_EXIT_QUAL, &exit_qual); - - struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual; - struct v3_io_hook * hook = v3_get_io_hook(info, io_qual->port); - int read_size; - addr_t guest_va; - addr_t host_addr; - int rdi_change; +int v3_handle_vmx_io_ins(struct guest_info * info) { + struct vmx_exit_io_qual io_qual; + struct v3_io_hook * hook = NULL; + int read_size = 0; + addr_t guest_va = 0; + addr_t host_addr = 0; + int rdi_change = 0; ulong_t rep_num = 1; + struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags); + int instr_len = 0; + + io_qual.value = 0; + vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value)); + hook = v3_get_io_hook(info, io_qual.port); - if(hook == NULL) { - PrintError("Hook not present for INS on port 0x%x\n", io_qual->port); + if (hook == NULL) { + PrintError("Hook not present for INS on port 0x%x\n", io_qual.port); return -1; } - PrintDebug("INS on port 0x%x\n", io_qual->port); + PrintDebug("INS on port 0x%x\n", io_qual.port); + + read_size = io_qual.access_size + 1; - read_size = io_qual->access_size + 1; + if (io_qual.rep) { + struct vmx_exit_io_instr_info instr_info; - if (io_qual->rep) { - rep_num = info->vm_regs.rcx & get_gpr_mask(info); + instr_info.value = 0; + vmcs_read(VMCS_EXIT_INSTR_INFO, &instr_info.value); + + if (instr_info.addr_size == 0) { + rep_num = info->vm_regs.rcx & 0xffff; + } else if(instr_info.addr_size == 1) { + rep_num = info->vm_regs.rcx & 0xffffffff; + } else if(instr_info.addr_size == 2) { + rep_num = info->vm_regs.rcx & 0xffffffffffffffffLL; + } else { + PrintDebug("Unknown INS address size!\n"); + return -1; + } } - if ( ((struct rflags *)&(info->ctrl_regs.rflags))->df ) { + if (flags->df) { rdi_change = -read_size; } else { rdi_change = read_size; @@ -139,25 +149,22 @@ int v3_handle_vmx_io_ins(struct guest_info * info) } do { - if (hook->read(io_qual->port, (char *)host_addr, read_size, hook->priv_data) != read_size) { - PrintError("Read Failure for INS on port 0x%x\n", io_qual->port); + if (hook->read(io_qual.port, (char *)host_addr, read_size, hook->priv_data) != read_size) { + PrintError("Read Failure for INS on port 0x%x\n", io_qual.port); return -1; } host_addr += rdi_change; info->vm_regs.rdi += rdi_change; - if (io_qual->rep) { - --info->vm_regs.rcx; + if (io_qual.rep) { + info->vm_regs.rcx--; } - --rep_num; - - } while (rep_num > 0); + + } while (--rep_num > 0); - int instr_len = 0; vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); - info->rip += instr_len; return 0; @@ -166,30 +173,28 @@ int v3_handle_vmx_io_ins(struct guest_info * info) int v3_handle_vmx_io_out(struct guest_info * info) { - ulong_t exit_qual; - - vmcs_read(VMCS_EXIT_QUAL, &exit_qual); - - struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual; + struct vmx_exit_io_qual io_qual; + struct v3_io_hook * hook = NULL; + int write_size = 0; + uint32_t instr_length = 0; - struct v3_io_hook * hook = v3_get_io_hook(info, io_qual->port); + vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value)); + hook = v3_get_io_hook(info, io_qual.port); if (hook == NULL) { - PrintError("Hook not present for out on port %x\n", io_qual->port); + PrintError("Hook not present for out on port %x\n", io_qual.port); return -1; } - int write_size = io_qual->access_size + 1; + write_size = io_qual.access_size + 1; - PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual->port, io_qual->port); + PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual.port, io_qual.port); - - if (hook->write(io_qual->port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) { - PrintError("Write failure for out on port %x\n",io_qual->port); + if (hook->write(io_qual.port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) { + PrintError("Write failure for out on port %x\n",io_qual.port); return -1; } - uint32_t instr_length = 0; if (vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_length) != VMX_SUCCESS) { PrintError("Could not read instruction length\n"); @@ -204,33 +209,48 @@ int v3_handle_vmx_io_out(struct guest_info * info) { int v3_handle_vmx_io_outs(struct guest_info * info) { - ulong_t exit_qual; - - vmcs_read(VMCS_EXIT_QUAL, &exit_qual); - - struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual; - struct v3_io_hook * hook = v3_get_io_hook(info, io_qual->port); + struct vmx_exit_io_qual io_qual; + struct v3_io_hook * hook = NULL; int write_size; addr_t guest_va; addr_t host_addr; int rsi_change; ulong_t rep_num = 1; + struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags); + int instr_len = 0; + + vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value)); + hook = v3_get_io_hook(info, io_qual.port); if (hook == NULL) { - PrintError("Hook not present for OUTS on port 0x%x\n", io_qual->port); + PrintError("Hook not present for OUTS on port 0x%x\n", io_qual.port); return -1; } - PrintDebug("OUTS on port 0x%x\n", io_qual->port); + PrintDebug("OUTS on port 0x%x\n", io_qual.port); - write_size = io_qual->access_size + 1; + write_size = io_qual.access_size + 1; - if (io_qual->rep) { + if (io_qual.rep) { // Grab the address sized bits of rcx - rep_num = info->vm_regs.rcx & get_gpr_mask(info); + struct vmx_exit_io_instr_info instr_info; + + instr_info.value = 0; + vmcs_read(VMCS_EXIT_INSTR_INFO, &instr_info.value); + + if (instr_info.addr_size == 0) { + rep_num = info->vm_regs.rcx & 0xffff; + } else if(instr_info.addr_size == 1) { + rep_num = info->vm_regs.rcx & 0xffffffff; + } else if(instr_info.addr_size == 2) { + rep_num = info->vm_regs.rcx & 0xffffffffffffffffLL; + } else { + PrintDebug("Unknown INS address size!\n"); + return -1; + } } - if ( ((struct rflags *)&(info->ctrl_regs.rflags))->df ) { + if (flags->df) { rsi_change = -write_size; } else { rsi_change = write_size; @@ -246,25 +266,22 @@ int v3_handle_vmx_io_outs(struct guest_info * info) { } do { - if (hook->write(io_qual->port, (char *)host_addr, write_size, hook->priv_data) != write_size) { - PrintError("Read failure for INS on port 0x%x\n", io_qual->port); + if (hook->write(io_qual.port, (char *)host_addr, write_size, hook->priv_data) != write_size) { + PrintError("Read failure for INS on port 0x%x\n", io_qual.port); return -1; } host_addr += rsi_change; info->vm_regs.rsi += rsi_change; - if (io_qual->rep) { + if (io_qual.rep) { --info->vm_regs.rcx; } - --rep_num; - } while (rep_num > 0); + } while (--rep_num > 0); - int instr_len = 0; vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len); - info->rip += instr_len; return 0; diff --git a/palacios/src/palacios/vmx_lowlevel.S b/palacios/src/palacios/vmx_lowlevel.S index 12aeb4b..4d0e82c 100644 --- a/palacios/src/palacios/vmx_lowlevel.S +++ b/palacios/src/palacios/vmx_lowlevel.S @@ -23,7 +23,7 @@ pushq %rbx; \ movq 8(%rsp), %rbx; \ movq %rbx, 56(%rax); \ - popq %rbx; \ + popq %rbx; \ \ movq %r8, 64(%rax); \ movq %r9, 72(%rax); \ @@ -35,7 +35,6 @@ movq %r15, 120(%rax); \ popq %rax; - #define restore_registers(location) \ mov location, %rax; \ mov (%rax), %rdi; \ @@ -56,10 +55,25 @@ pushq %rbx; \ movq 56(%rax), %rbx; \ movq %rbx, %rax; \ - popq %rbx; - - + popq %rbx;; +#define save_ctrl_regs(location) \ + pushq %rax; \ + pushq %rbx; \ + movq location, %rax; \ + movq %cr2, %rbx; \ + movq %rbx, 8(%rax); \ + popq %rbx; \ + popq %rax + +#define restore_ctrl_regs(location) \ + pushq %rax; \ + pushq %rbx; \ + movq location, %rax; \ + movq 8(%rax), %rbx; \ + movq %rbx, %cr2; \ + popq %rbx; \ + popq %rax #define PUSHA \ push %rax; \ @@ -98,40 +112,50 @@ .align 8 .globl v3_vmx_exit_handler v3_vmx_exit_handler: - save_registers(8(%rsp)); - addq $8, %rsp + // the save_* argument is a macro expansion; it has to jump past any pushes in the macro + // stack: vm_regs ptr, ctrl_regs_ptr + // save registers macro stack: vm_regs ptr, ctrl_regs ptr, pushed rax + // save_ctrl_regs macro stack: vm_regs ptr, ctrl_regs_ptr, pushed rax, pushed rbx + // Both macros jump past 2 saved values to reach their pointers, so both are 16(rsp) + save_registers(16(%rsp)); + save_ctrl_regs(16(%rsp)); + addq $16, %rsp POPA popf pushq %rdi pushq %rsi + pushq %rdx call v3_handle_vmx_exit andq %rax, %rax jnz .Lvmm_failure v3_vmx_vmresume: + pop %rdx pop %rsi pop %rdi pushf PUSHA pushq %rdi + pushq %rdx + restore_ctrl_regs(%rdx); restore_registers(%rdi); vmresume jz .Lfail_valid jc .Lfail_invalid - addq $8, %rsp + addq $16, %rsp jmp .Lreturn .align 8 .globl v3_vmx_vmlaunch -// vm_regs = %rdi +// vm_regs = %rdi, guest_info * = %rsi, ctrl_regs = %rdx v3_vmx_vmlaunch: - cli pushf PUSHA pushq %rdi + pushq %rdx movq %rsp, %rax movq $VMCS_HOST_RSP, %rbx @@ -145,6 +169,7 @@ v3_vmx_vmlaunch: jz .Lfail_valid jc .Lfail_invalid + restore_ctrl_regs(%rdx); restore_registers(%rdi); vmlaunch @@ -153,21 +178,21 @@ v3_vmx_vmlaunch: jmp .Lreturn .Lfail_valid: - addq $8, %rsp + addq $16, %rsp POPA popf movq $VMX_FAIL_VALID, %rax jmp .Lreturn .Lfail_invalid: - addq $8, %rsp + addq $16, %rsp POPA popf movq $VMX_FAIL_INVALID, %rax jmp .Lreturn .Lvmm_failure: - addq $16, %rsp + addq $24, %rsp movq $VMM_FAILURE, %rax jmp .Lreturn diff --git a/palacios/src/palacios/vmx_msr.c b/palacios/src/palacios/vmx_msr.c index fa53ffc..66995ac 100644 --- a/palacios/src/palacios/vmx_msr.c +++ b/palacios/src/palacios/vmx_msr.c @@ -19,29 +19,46 @@ #include #include +#include + +#define LOW_MSR_START 0x00000000 +#define LOW_MSR_END 0x1fff +#define HIGH_MSR_START 0xc0000000 +#define HIGH_MSR_END 0xc0001fff + +#define LOW_MSR_INDEX 0 +#define HIGH_MSR_INDEX 1024 + +static int get_bitmap_index(uint_t msr) +{ + if( (msr >= LOW_MSR_START) && msr <= LOW_MSR_END) { + return LOW_MSR_INDEX + msr; + } else if (( msr >= HIGH_MSR_START ) && (msr <= HIGH_MSR_END)) { + return HIGH_MSR_INDEX + (msr - HIGH_MSR_START); + } else { + PrintError("MSR out of range: 0x%x\n", msr); + return -1; + } +} /* Same as SVM */ static int update_map(struct guest_info * info, uint_t msr, int hook_reads, int hook_writes) { -#if 0 int index = get_bitmap_index(msr); - uint_t major = index / 4; - uint_t minor = (index % 4) * 2; - uchar_t val = 0; - uchar_t mask = 0x3; + uint_t major = index / 8; + uint_t minor = (index % 8); + uchar_t mask = 0x1; + uint8_t read_val = (hook_reads) ? 0x1 : 0x0; + uint8_t write_val = (hook_writes) ? 0x1 : 0x0; uint8_t * bitmap = (uint8_t *)(info->msr_map.arch_data); - if (hook_reads) { - val |= 0x1; - } - - if (hook_writes) { - val |= 0x2; - } *(bitmap + major) &= ~(mask << minor); - *(bitmap + major) |= (val << minor); -#endif + *(bitmap + major) |= (read_val << minor); + + + *(bitmap + 2048 + major) &= ~(mask << minor); + *(bitmap + 2048 + major) |= (write_val << minor); return 0; }