diff options
-rw-r--r-- | sys/arch/amd64/amd64/vmm.c | 56 | ||||
-rw-r--r-- | usr.sbin/vmd/loadfile.h | 10 | ||||
-rw-r--r-- | usr.sbin/vmd/loadfile_elf.c | 39 | ||||
-rw-r--r-- | usr.sbin/vmd/vmm.c | 9 |
4 files changed, 90 insertions, 24 deletions
diff --git a/sys/arch/amd64/amd64/vmm.c b/sys/arch/amd64/amd64/vmm.c index c633c72d46d..36623121521 100644 --- a/sys/arch/amd64/amd64/vmm.c +++ b/sys/arch/amd64/amd64/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.46 2016/04/04 16:47:34 stefan Exp $ */ +/* $OpenBSD: vmm.c,v 1.47 2016/04/05 09:33:05 mlarkin Exp $ */ /* * Copyright (c) 2014 Mike Larkin <mlarkin@openbsd.org> * @@ -1245,15 +1245,16 @@ vcpu_reset_regs_svm(struct vcpu *vcpu, struct vcpu_init_state *vis) int vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_init_state *vis) { - int ret; + int ret, ug; uint32_t cr0, cr4; uint32_t pinbased, procbased, procbased2, exit, entry; uint32_t want1, want0; - uint64_t msr, ctrlval, eptp, vmcs_ptr; + uint64_t msr, ctrlval, eptp, vmcs_ptr, cr3; uint16_t ctrl; struct vmx_msr_store *msr_store; ret = 0; + ug = 0; /* Flush any old state */ if (!vmptrst(&vmcs_ptr)) { @@ -1443,8 +1444,10 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_init_state *vis) if (vcpu_vmx_check_cap(vcpu, IA32_VMX_PROCBASED_CTLS, IA32_VMX_ACTIVATE_SECONDARY_CONTROLS, 1)) { if (vcpu_vmx_check_cap(vcpu, IA32_VMX_PROCBASED2_CTLS, - IA32_VMX_UNRESTRICTED_GUEST, 1)) + IA32_VMX_UNRESTRICTED_GUEST, 1)) { want1 |= IA32_VMX_UNRESTRICTED_GUEST; + ug = 1; + } } want0 = ~want1; @@ -1495,12 +1498,17 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_init_state *vis) /* * Entry ctrls * + * We must be able to set the following: + * IA32_VMX_IA32E_MODE_GUEST (if no unrestricted guest) * We must be able to clear the following: * IA32_VMX_ENTRY_TO_SMM - enter to SMM * IA32_VMX_DEACTIVATE_DUAL_MONITOR_TREATMENT * XXX clear load debug_ctrls on entry ? */ - want1 = 0; + if (ug == 1) + want1 = 0; + else + want1 = IA32_VMX_IA32E_MODE_GUEST; want0 = IA32_VMX_ENTRY_TO_SMM | IA32_VMX_DEACTIVATE_DUAL_MONITOR_TREATMENT; @@ -1530,7 +1538,6 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_init_state *vis) eptp |= ((IA32_EPT_PAGE_WALK_LENGTH - 1) << 3); } - if (msr & IA32_EPT_VPID_CAP_WB) { /* WB cache type supported */ eptp |= IA32_EPT_PAGING_CACHE_TYPE_WB; @@ -1597,15 +1604,14 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_init_state *vis) * any value for CR0_PG and CR0_PE in vis->vis_cr0 if the CPU has * the unrestricted guest capability. */ - if (vcpu_vmx_check_cap(vcpu, IA32_VMX_PROCBASED_CTLS, - IA32_VMX_ACTIVATE_SECONDARY_CONTROLS, 1)) { - if (vcpu_vmx_check_cap(vcpu, IA32_VMX_PROCBASED2_CTLS, - IA32_VMX_UNRESTRICTED_GUEST, 1)) - want1 &= ~(CR0_PG | CR0_PE); - want0 &= ~(CR0_PG | CR0_PE); + cr0 = vis->vis_cr0; + + if (ug) { + want1 &= ~(CR0_PG | CR0_PE); + want0 &= ~(CR0_PG | CR0_PE); + cr0 &= ~(CR0_PG | CR0_PE); } - cr0 = vis->vis_cr0; /* * VMX may require some bits to be set that userland should not have @@ -1628,7 +1634,12 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_init_state *vis) goto exit; } - if (vmwrite(VMCS_GUEST_IA32_CR3, vis->vis_cr3)) { + if (ug) + cr3 = 0; + else + cr3 = vis->vis_cr3; + + if (vmwrite(VMCS_GUEST_IA32_CR3, cr3)) { ret = EINVAL; goto exit; } @@ -1640,6 +1651,12 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_init_state *vis) cr4 = (curcpu()->ci_vmm_cap.vcc_vmx.vmx_cr4_fixed0) & (curcpu()->ci_vmm_cap.vcc_vmx.vmx_cr4_fixed1); + /* + * If we are starting in restricted guest mode, enable PAE + */ + if (ug == 0) + cr4 |= CR4_PAE; + if (vmwrite(VMCS_GUEST_IA32_CR4, cr4)) { ret = EINVAL; goto exit; @@ -1853,8 +1870,17 @@ vcpu_reset_regs_vmx(struct vcpu *vcpu, struct vcpu_init_state *vis) * Select MSRs to be loaded on entry / saved on exit */ msr_store = (struct vmx_msr_store *)vcpu->vc_vmx_msr_exit_save_va; + + /* + * Make sure LME is enabled in EFER if restricted guest mode is + * needed. + */ msr_store[0].vms_index = MSR_EFER; - msr_store[0].vms_data = 0ULL; /* Initial value */ + if (ug == 1) + msr_store[0].vms_data = 0ULL; /* Initial value */ + else + msr_store[0].vms_data = EFER_LME; + msr_store[1].vms_index = MSR_CR_PAT; msr_store[1].vms_data = 0ULL; /* Initial value */ msr_store[2].vms_index = MSR_STAR; diff --git a/usr.sbin/vmd/loadfile.h b/usr.sbin/vmd/loadfile.h index 4b473425550..19534e09683 100644 --- a/usr.sbin/vmd/loadfile.h +++ b/usr.sbin/vmd/loadfile.h @@ -1,5 +1,5 @@ /* $NetBSD: loadfile.h,v 1.1 1999/04/28 09:08:50 christos Exp $ */ -/* $OpenBSD: loadfile.h,v 1.3 2016/03/13 13:11:47 stefan Exp $ */ +/* $OpenBSD: loadfile.h,v 1.4 2016/04/05 09:33:05 mlarkin Exp $ */ /*- * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -65,6 +65,14 @@ #define LOWMEM_KB 636 +#define BOOTARGS_PAGE 0x2000 +#define STACK_PAGE 0xF000 +#define GDT_PAGE 0x10000 +#define PML4_PAGE 0x11000 +#define PML3_PAGE 0x12000 +#define PML2_PAGE 0x13000 +#define NPTE_PG (PAGE_SIZE / sizeof(pt_entry_t)) + int loadelf_main(int, struct vm_create_params *, struct vcpu_init_state *); diff --git a/usr.sbin/vmd/loadfile_elf.c b/usr.sbin/vmd/loadfile_elf.c index 10a5ad80d83..8d2e68b25b0 100644 --- a/usr.sbin/vmd/loadfile_elf.c +++ b/usr.sbin/vmd/loadfile_elf.c @@ -1,5 +1,5 @@ /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */ -/* $OpenBSD: loadfile_elf.c,v 1.12 2016/04/04 17:13:54 stefan Exp $ */ +/* $OpenBSD: loadfile_elf.c,v 1.13 2016/04/05 09:33:05 mlarkin Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -100,14 +100,11 @@ #include <machine/vmmvar.h> #include <machine/biosvar.h> #include <machine/segments.h> +#include <machine/pte.h> #include "loadfile.h" #include "vmd.h" -#define BOOTARGS_PAGE 0x2000 -#define GDT_PAGE 0x10000 -#define STACK_PAGE 0xF000 - union { Elf32_Ehdr elf32; Elf64_Ehdr elf64; @@ -195,6 +192,37 @@ push_gdt(void) } /* + * push_pt + * + * Create an identity-mapped page directory hierarchy mapping the first + * 1GB of physical memory. This is used during bootstrapping VMs on + * CPUs without unrestricted guest capability. + */ +static void +push_pt(void) +{ + pt_entry_t ptes[NPTE_PG]; + uint64_t i; + + /* PML3 [0] - first 1GB */ + memset(ptes, 0, sizeof(ptes)); + ptes[0] = PG_V | PML3_PAGE; + write_mem(PML4_PAGE, ptes, PAGE_SIZE); + + /* PML3 [0] - first 1GB */ + memset(ptes, 0, sizeof(ptes)); + ptes[0] = PG_V | PG_RW | PG_u | PML2_PAGE; + write_mem(PML3_PAGE, ptes, PAGE_SIZE); + + /* PML2 [0..511] - first 1GB (in 2MB pages) */ + memset(ptes, 0, sizeof(ptes)); + for (i = 0 ; i < NPTE_PG; i++) { + ptes[i] = PG_V | PG_RW | PG_u | PG_PS | (NBPD_L2 * i); + } + write_mem(PML2_PAGE, ptes, PAGE_SIZE); +} + +/* * loadelf_main * * Loads an ELF kernel to it's defined load address in the guest VM. @@ -234,6 +262,7 @@ loadelf_main(int fd, struct vm_create_params *vcp, struct vcpu_init_state *vis) return (r); push_gdt(); + push_pt(); n = create_bios_memmap(vcp, memmap); bootargsz = push_bootargs(memmap, n); stacksize = push_stack(bootargsz, marks[MARK_END]); diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c index 521a08beb7f..8c7eddf2df7 100644 --- a/usr.sbin/vmd/vmm.c +++ b/usr.sbin/vmd/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.24 2016/04/04 17:13:54 stefan Exp $ */ +/* $OpenBSD: vmm.c,v 1.25 2016/04/05 09:33:05 mlarkin Exp $ */ /* * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> @@ -161,13 +161,16 @@ static struct privsep_proc procs[] = { * * Specific bootloaders should clone this structure and override * those fields as needed. + * + * Note - CR3 and various bits in CR0 may be overridden by vmm(4) based on + * features of the CPU in use. */ static const struct vcpu_init_state vcpu_init_flat32 = { 0x2, /* RFLAGS */ 0x0, /* RIP */ 0x0, /* RSP */ - CR0_CD | CR0_NW | CR0_ET | CR0_PE, /* CR0 */ - 0x0, /* CR3 */ + CR0_CD | CR0_NW | CR0_ET | CR0_PE | CR0_PG, /* CR0 */ + PML4_PAGE, /* CR3 */ { 0x8, 0xFFFFFFFF, 0xC09F, 0x0}, /* CS */ { 0x10, 0xFFFFFFFF, 0xC093, 0x0}, /* DS */ { 0x10, 0xFFFFFFFF, 0xC093, 0x0}, /* ES */ |