diff --git a/palacios/include/palacios/vmm_regs.h b/palacios/include/palacios/vmm_regs.h index e116d43..310ff06 100644 --- a/palacios/include/palacios/vmm_regs.h +++ b/palacios/include/palacios/vmm_regs.h @@ -54,6 +54,12 @@ struct v3_ctrl_regs { v3_reg_t apic_tpr; // cr8 is (apic_tpr >> 4) & 0xf v3_reg_t rflags; v3_reg_t efer; + + // On Intel without unrestricted guest mode, we need + // to cache CR4 and CR3 writes while the guest thinks + // paging is disabled. + v3_reg_t cached_cr3; + v3_reg_t cached_cr4; }; diff --git a/palacios/include/palacios/vmx_ctrl_regs.h b/palacios/include/palacios/vmx_ctrl_regs.h index 441b1e5..0ce3cfd 100644 --- a/palacios/include/palacios/vmx_ctrl_regs.h +++ b/palacios/include/palacios/vmx_ctrl_regs.h @@ -35,6 +35,12 @@ int v3_vmx_handle_cr4_access(struct guest_info * info, struct vmx_exit_cr_qual * cr_qual); int v3_vmx_handle_cr8_access(struct guest_info * info, struct vmx_exit_cr_qual * cr_qual); +int v3_vmx_bootstrap_efer_read(struct guest_info * info, + uint_t msr, struct v3_msr * dst, + void * priv_data); +int v3_vmx_bootstrap_efer_write(struct guest_info * info, + uint_t msr, struct v3_msr src, + void * priv_data); #endif diff --git a/palacios/src/palacios/vmx.c b/palacios/src/palacios/vmx.c index 6fd1f8d..62f7d1a 100644 --- a/palacios/src/palacios/vmx.c +++ b/palacios/src/palacios/vmx.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef V3_CONFIG_CHECKPOINT #include @@ -296,6 +297,7 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state) } else if ((core->shdw_pg_mode == NESTED_PAGING) && (v3_mach_type == V3_VMX_EPT_CPU)) { + // This is the path taken for Intel without unrestricted guest mode #define CR0_PE 0x00000001 #define CR0_PG 0x80000000 @@ -308,9 +310,9 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state) // Cause VM_EXIT whenever CR4.VMXE or CR4.PAE bits are written vmx_ret |= check_vmcs_write(VMCS_CR4_MASK, CR4_VMXE | CR4_PAE); - /* Disable CR exits */ - vmx_state->pri_proc_ctrls.cr3_ld_exit = 0; - vmx_state->pri_proc_ctrls.cr3_str_exit = 0; + // We have to enable CR3 exits until the guest explicitly enables paging + vmx_state->pri_proc_ctrls.cr3_ld_exit = 1; + vmx_state->pri_proc_ctrls.cr3_str_exit = 1; vmx_state->pri_proc_ctrls.invlpg_exit = 0; @@ -332,12 +334,12 @@ static int init_vmcs_bios(struct guest_info * core, struct vmx_data * vmx_state) } // Hook all accesses to EFER register - v3_hook_msr(core->vm_info, EFER_MSR, NULL, NULL, NULL); + v3_hook_msr(core->vm_info, EFER_MSR, &v3_vmx_bootstrap_efer_read, &v3_vmx_bootstrap_efer_write, core); } else if ((core->shdw_pg_mode == NESTED_PAGING) && (v3_mach_type == V3_VMX_EPT_UG_CPU)) { + // This is the path taken for Intel with unrestricted guest mode int i = 0; - // For now we will assume that unrestricted guest mode is assured w/ EPT core->vm_regs.rsp = 0x00; diff --git a/palacios/src/palacios/vmx_ctrl_regs.c b/palacios/src/palacios/vmx_ctrl_regs.c index 8a7c3bf..34defc0 100644 --- a/palacios/src/palacios/vmx_ctrl_regs.c +++ b/palacios/src/palacios/vmx_ctrl_regs.c @@ -81,11 +81,21 @@ int v3_vmx_handle_cr4_access(struct guest_info * info, struct vmx_exit_cr_qual * if (cr_qual->access_type < 2) { if (cr_qual->access_type == 0) { + v3_reg_t orig_cr4 = info->ctrl_regs.cr4; + if (v3_handle_cr4_write(info) != 0) { PrintError(info->vm_info, info, "Could not handle CR4 write\n"); return -1; } info->ctrl_regs.cr4 |= 0x2000; // no VMX allowed in guest, so mask CR4.VMXE + + // If on Intel without unrestricted guest mode, we have to + // cache CR4 writes until the guest actually turns on paging. + if (info->ctrl_regs.cr3 == VMXASSIST_1to1_PT) { + info->ctrl_regs.cached_cr4 = info->ctrl_regs.cr4; + info->ctrl_regs.cr4 = orig_cr4; + } + } else { if (v3_handle_cr4_read(info) != 0) { PrintError(info->vm_info, info, "Could not handle CR4 read\n"); @@ -122,6 +132,16 @@ int v3_vmx_handle_cr8_access(struct guest_info * info, struct vmx_exit_cr_qual * return -1; } +int v3_vmx_bootstrap_efer_read(struct guest_info * info, uint_t msr, struct v3_msr * dst, void * priv_data) { + dst->value = info->shdw_pg_state.guest_efer.value; + return 0; +} + +int v3_vmx_bootstrap_efer_write(struct guest_info * info, uint_t msr, struct v3_msr src, void * priv_data) { + info->shdw_pg_state.guest_efer.value = src.value; + return 0; +} + static int handle_mov_to_cr3(struct guest_info * info, v3_reg_t * cr3_reg) { if (info->shdw_pg_mode == SHADOW_PAGING) { @@ -151,12 +171,11 @@ static int handle_mov_to_cr3(struct guest_info * info, v3_reg_t * cr3_reg) { (void *)info->shdw_pg_state.guest_cr3); */ } else if (info->shdw_pg_mode == NESTED_PAGING) { - PrintError(info->vm_info, info, "Nested paging not available in VMX right now!\n"); - return -1; + // On Intel without unrestricted guest mode, we have to cache CR3 + // writes until the guest actually enables paging. + info->ctrl_regs.cached_cr3 = *cr3_reg; } - - return 0; } @@ -262,6 +281,7 @@ static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t * new_cr0, struc struct efer_64 * hw_efer = (struct efer_64 *)&(info->ctrl_regs.efer); if (vmx_info->assist_state != VMXASSIST_DISABLED) { + // This path is entered on Intel without unrestricted guest mode if (vm_efer->lme) { PrintDebug(info->vm_info, info, "Enabling long mode\n"); @@ -269,6 +289,20 @@ static int handle_mov_to_cr0(struct guest_info * info, v3_reg_t * new_cr0, struc hw_efer->lme = 1; vmx_info->entry_ctrls.guest_ia32e = 1; + + // Special case code to handle Intel without unrestricted guest mode support + if (info->ctrl_regs.cr3 == VMXASSIST_1to1_PT) { + // We can finally write the hardware CR3 and CR4 regs + info->ctrl_regs.cr3 = info->ctrl_regs.cached_cr3; + info->ctrl_regs.cr4 = info->ctrl_regs.cached_cr4; + + // Now that long mode is enabled, + // we can stop intercepting CR3 and EFER accesses + vmx_info->pri_proc_ctrls.cr3_ld_exit = 0; + vmx_info->pri_proc_ctrls.cr3_str_exit = 0; + v3_hook_msr(info->vm_info, EFER_MSR, NULL, NULL, NULL); + v3_update_vmcs_ctrl_fields(info); + } } } else { if (hw_efer->lme) {