summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/amd64/amd64/vmm.c56
-rw-r--r--usr.sbin/vmd/loadfile.h10
-rw-r--r--usr.sbin/vmd/loadfile_elf.c39
-rw-r--r--usr.sbin/vmd/vmm.c9
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 */