X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmx_ctrl_regs.c;h=8fb7a81952f9d6e249f86b3e7a8b5563f92d6515;hp=10503b4ff50649e2d19b26d80a5e6016f32b74fc;hb=cfcceed5890430afedcc544bd7dbb69e29dfd65a;hpb=19c179d8c8a23c2612f9c12ec7cbedc299ce80e5 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; } +