svn commit: r253137 - in projects/bhyve_npt_pmap: sys/amd64/include sys/amd64/vmm sys/amd64/vmm/intel usr.sbin/bhyve

Neel Natu neel at FreeBSD.org
Wed Jul 10 07:22:01 UTC 2013


Author: neel
Date: Wed Jul 10 07:21:59 2013
New Revision: 253137
URL: http://svnweb.freebsd.org/changeset/base/253137

Log:
  Move instruction emulation out of the critical section since it may need
  to sleep waiting for the underlying page to be swapped in.
  
  The processor-specific code now simply identifies the EPT fault as one
  triggered during instruction execution and fills in the collateral (e.g.
  gpa, gla, cr3).
  
  The instruction fetch, decode and emulation is then done in the vm_run
  loop.

Modified:
  projects/bhyve_npt_pmap/sys/amd64/include/vmm.h
  projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c
  projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c
  projects/bhyve_npt_pmap/sys/amd64/vmm/vmm_dev.c
  projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c

Modified: projects/bhyve_npt_pmap/sys/amd64/include/vmm.h
==============================================================================
--- projects/bhyve_npt_pmap/sys/amd64/include/vmm.h	Wed Jul 10 07:15:39 2013	(r253136)
+++ projects/bhyve_npt_pmap/sys/amd64/include/vmm.h	Wed Jul 10 07:21:59 2013	(r253137)
@@ -96,7 +96,6 @@ int vm_unmap_mmio(struct vm *vm, vm_padd
 void *vm_gpa_hold(struct vm *, vm_paddr_t gpa, size_t len, int prot,
 		  void **cookie);
 void vm_gpa_release(void *cookie);
-vm_paddr_t vm_gpa2hpa(struct vm *vm, vm_paddr_t gpa, size_t size);
 int vm_gpabase2memseg(struct vm *vm, vm_paddr_t gpabase,
 	      struct vm_memory_segment *seg);
 int vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len,
@@ -254,6 +253,7 @@ enum vm_exitcode {
 	VM_EXITCODE_MTRAP,
 	VM_EXITCODE_PAUSE,
 	VM_EXITCODE_PAGING,
+	VM_EXITCODE_INST_EMUL,
 	VM_EXITCODE_SPINUP_AP,
 	VM_EXITCODE_MAX
 };
@@ -273,10 +273,14 @@ struct vm_exit {
 		} inout;
 		struct {
 			uint64_t	gpa;
-			struct vie	vie;
-			int		inst_emulation;
 			int		fault_type;
 		} paging;
+		struct {
+			uint64_t	gpa;
+			uint64_t	gla;
+			uint64_t	cr3;
+			struct vie	vie;
+		} inst_emul;
 		/*
 		 * VMX specific payload. Used when there is no "better"
 		 * exitcode to represent the VM-exit.

Modified: projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c	Wed Jul 10 07:15:39 2013	(r253136)
+++ projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c	Wed Jul 10 07:21:59 2013	(r253137)
@@ -49,8 +49,6 @@ __FBSDID("$FreeBSD$");
 #include <machine/specialreg.h>
 #include <machine/vmparam.h>
 
-#include <x86/apicreg.h>
-
 #include <machine/vmm.h>
 #include "vmm_host.h"
 #include "vmm_lapic.h"
@@ -1189,22 +1187,20 @@ ept_fault_type(uint64_t ept_qual)
 	return (fault_type);
 }
 
-static int
-vmx_inst_emul(struct vm *vm, int cpu,
-	      uint64_t gla, uint64_t gpa, uint64_t rip, int inst_length,
-	      uint64_t cr3, uint64_t ept_qual, struct vie *vie)
+static boolean_t
+ept_emulation_fault(uint64_t ept_qual)
 {
-	int read, write, error;
+	int read, write;
 
-	/* EPT violation on an instruction fetch doesn't make sense here */
+	/* EPT fault on an instruction fetch doesn't make sense here */
 	if (ept_qual & EPT_VIOLATION_INST_FETCH)
-		return (UNHANDLED);
+		return (FALSE);
 
-	/* EPT violation must be a read fault or a write fault */
+	/* EPT fault must be a read fault or a write fault */
 	read = ept_qual & EPT_VIOLATION_DATA_READ ? 1 : 0;
 	write = ept_qual & EPT_VIOLATION_DATA_WRITE ? 1 : 0;
 	if ((read | write) == 0)
-		return (UNHANDLED);
+		return (FALSE);
 
 	/*
 	 * The EPT violation must have been caused by accessing a
@@ -1213,36 +1209,20 @@ vmx_inst_emul(struct vm *vm, int cpu,
 	 */
 	if ((ept_qual & EPT_VIOLATION_GLA_VALID) == 0 ||
 	    (ept_qual & EPT_VIOLATION_XLAT_VALID) == 0) {
-		return (UNHANDLED);
+		return (FALSE);
 	}
 
-	/* Fetch, decode and emulate the faulting instruction */
-	if (vmm_fetch_instruction(vm, cpu, rip, inst_length, cr3, vie) != 0)
-		return (UNHANDLED);
-
-	if (vmm_decode_instruction(vm, cpu, gla, vie) != 0)
-		return (UNHANDLED);
-
-	/*
-	 * Check if this is a local apic access
-	 */
-	if (gpa < DEFAULT_APIC_BASE || gpa >= DEFAULT_APIC_BASE + PAGE_SIZE)
-		return (UNHANDLED);
-
-	error = vmm_emulate_instruction(vm, cpu, gpa, vie,
-					lapic_mmio_read, lapic_mmio_write, 0);
-
-	return (error ? UNHANDLED : HANDLED);
+	return (TRUE);
 }
 
 static int
 vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
 {
-	int error, handled, emulation;
+	int error, handled;
 	struct vmcs *vmcs;
 	struct vmxctx *vmxctx;
 	uint32_t eax, ecx, edx;
-	uint64_t qual, gla, gpa, cr3, intr_info;
+	uint64_t qual, gpa, intr_info;
 
 	handled = 0;
 	vmcs = &vmx->vmcs[vcpu];
@@ -1356,23 +1336,14 @@ vmx_exit_process(struct vmx *vmx, int vc
 		 */
 		gpa = vmcs_gpa();
 		if (vm_mem_allocated(vmx->vm, gpa)) {
-			handled = 0;
-			emulation = 0;
-		} else {
-			emulation = 1;
-			gla = vmcs_gla();
-			cr3 = vmcs_guest_cr3();
-			vie_init(&vmexit->u.paging.vie);
-			handled = vmx_inst_emul(vmx->vm, vcpu, gla, gpa,
-					    vmexit->rip, vmexit->inst_length,
-					    cr3, qual, &vmexit->u.paging.vie);
-		}
-
-		if (!handled) {
 			vmexit->exitcode = VM_EXITCODE_PAGING;
 			vmexit->u.paging.gpa = gpa;
-			vmexit->u.paging.inst_emulation = emulation;
 			vmexit->u.paging.fault_type = ept_fault_type(qual);
+		} else if (ept_emulation_fault(qual)) {
+			vmexit->exitcode = VM_EXITCODE_INST_EMUL;
+			vmexit->u.inst_emul.gpa = gpa;
+			vmexit->u.inst_emul.gla = vmcs_gla();
+			vmexit->u.inst_emul.cr3 = vmcs_guest_cr3();
 		}
 		break;
 	default:
@@ -1394,14 +1365,6 @@ vmx_exit_process(struct vmx *vmx, int vc
 		vm_exit_update_rip(vmexit);
 		vmexit->rip += vmexit->inst_length;
 		vmexit->inst_length = 0;
-
-		/*
-		 * Special case for spinning up an AP - exit to userspace to
-		 * give the controlling process a chance to intercept and
-		 * spin up a thread for the AP.
-		 */
-		if (vmexit->exitcode == VM_EXITCODE_SPINUP_AP)
-			handled = 0;
 	} else {
 		if (vmexit->exitcode == VM_EXITCODE_BOGUS) {
 			/*

Modified: projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c
==============================================================================
--- projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c	Wed Jul 10 07:15:39 2013	(r253136)
+++ projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c	Wed Jul 10 07:21:59 2013	(r253137)
@@ -701,7 +701,7 @@ vcpu_require_state_locked(struct vcpu *v
  * Emulate a guest 'hlt' by sleeping until the vcpu is ready to run.
  */
 static int
-vcpu_sleep(struct vm *vm, int vcpuid, boolean_t *retu)
+vm_handle_hlt(struct vm *vm, int vcpuid, boolean_t *retu)
 {
 	struct vcpu *vcpu;
 	int sleepticks, t;
@@ -745,7 +745,7 @@ vcpu_sleep(struct vm *vm, int vcpuid, bo
 }
 
 static int
-vcpu_paging(struct vm *vm, int vcpuid, boolean_t *retu)
+vm_handle_paging(struct vm *vm, int vcpuid, boolean_t *retu)
 {
 	int rv;
 	struct thread *td;
@@ -758,12 +758,6 @@ vcpu_paging(struct vm *vm, int vcpuid, b
 	vcpu = &vm->vcpu[vcpuid];
 	vme = &vcpu->exitinfo;
 
-	/* Return to userspace to do the instruction emulation */
-	if (vme->u.paging.inst_emulation) {
-		*retu = TRUE;
-		return (0);
-	}
-
 	td = curthread;
 	p = td->td_proc;
 	map = &vm->vmspace->vm_map;
@@ -788,6 +782,52 @@ vcpu_paging(struct vm *vm, int vcpuid, b
 	return (0);
 }
 
+
+static int
+vm_handle_inst_emul(struct vm *vm, int vcpuid, boolean_t *retu)
+{
+	struct vie *vie;
+	struct vcpu *vcpu;
+	struct vm_exit *vme;
+	int error, inst_length;
+	uint64_t rip, gla, gpa, cr3;
+
+	vcpu = &vm->vcpu[vcpuid];
+	vme = &vcpu->exitinfo;
+
+	rip = vme->rip;
+	inst_length = vme->inst_length;
+
+	gla = vme->u.inst_emul.gla;
+	gpa = vme->u.inst_emul.gpa;
+	cr3 = vme->u.inst_emul.cr3;
+	vie = &vme->u.inst_emul.vie;
+
+	vie_init(vie);
+
+	/* Fetch, decode and emulate the faulting instruction */
+	if (vmm_fetch_instruction(vm, vcpuid, rip, inst_length, cr3, vie) != 0)
+		return (EFAULT);
+
+	if (vmm_decode_instruction(vm, vcpuid, gla, vie) != 0)
+		return (EFAULT);
+
+	/* return to userland unless this is a local apic access */
+	if (gpa < DEFAULT_APIC_BASE || gpa >= DEFAULT_APIC_BASE + PAGE_SIZE) {
+		*retu = TRUE;
+		return (0);
+	}
+
+	error = vmm_emulate_instruction(vm, vcpuid, gpa, vie,
+					lapic_mmio_read, lapic_mmio_write, 0);
+
+	/* return to userland to spin up the AP */
+	if (error == 0 && vme->exitcode == VM_EXITCODE_SPINUP_AP)
+		*retu = TRUE;
+
+	return (error);
+}
+
 int
 vm_run(struct vm *vm, struct vm_run *vmrun)
 {
@@ -834,10 +874,13 @@ restart:
 		retu = FALSE;
 		switch (vme->exitcode) {
 		case VM_EXITCODE_HLT:
-			error = vcpu_sleep(vm, vcpuid, &retu);
+			error = vm_handle_hlt(vm, vcpuid, &retu);
 			break;
 		case VM_EXITCODE_PAGING:
-			error = vcpu_paging(vm, vcpuid, &retu);
+			error = vm_handle_paging(vm, vcpuid, &retu);
+			break;
+		case VM_EXITCODE_INST_EMUL:
+			error = vm_handle_inst_emul(vm, vcpuid, &retu);
 			break;
 		default:
 			retu = TRUE;	/* handled in userland */

Modified: projects/bhyve_npt_pmap/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- projects/bhyve_npt_pmap/sys/amd64/vmm/vmm_dev.c	Wed Jul 10 07:15:39 2013	(r253136)
+++ projects/bhyve_npt_pmap/sys/amd64/vmm/vmm_dev.c	Wed Jul 10 07:21:59 2013	(r253137)
@@ -359,6 +359,8 @@ vmmdev_ioctl(struct cdev *cdev, u_long c
 	}
 
 done:
+	/* Make sure that no handler returns a bogus value like ERESTART */
+	KASSERT(error >= 0, ("vmmdev_ioctl: invalid error return %d", error));
 	return (error);
 }
 

Modified: projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c	Wed Jul 10 07:15:39 2013	(r253136)
+++ projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c	Wed Jul 10 07:21:59 2013	(r253137)
@@ -107,7 +107,7 @@ struct fbsdstats {
         uint64_t        vmexit_hlt;
         uint64_t        vmexit_pause;
         uint64_t        vmexit_mtrap;
-        uint64_t        vmexit_paging;
+        uint64_t        vmexit_inst_emul;
         uint64_t        cpu_switch_rotate;
         uint64_t        cpu_switch_direct;
         int             io_reset;
@@ -435,16 +435,13 @@ vmexit_mtrap(struct vmctx *ctx, struct v
 }
 
 static int
-vmexit_paging(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
+vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
 {
 	int err;
-	stats.vmexit_paging++;
+	stats.vmexit_inst_emul++;
 
-	if (vmexit->u.paging.inst_emulation) {
-		err = emulate_mem(ctx, *pvcpu, vmexit->u.paging.gpa,
-				  &vmexit->u.paging.vie);
-	} else
-		err = ESRCH;
+	err = emulate_mem(ctx, *pvcpu, vmexit->u.inst_emul.gpa,
+			  &vmexit->u.inst_emul.vie);
 
 	if (err) {
 		if (err == EINVAL) {
@@ -453,7 +450,7 @@ vmexit_paging(struct vmctx *ctx, struct 
 			    vmexit->rip);
 		} else if (err == ESRCH) {
 			fprintf(stderr, "Unhandled memory access to 0x%lx\n",
-			    vmexit->u.paging.gpa);
+			    vmexit->u.inst_emul.gpa);
 		}
 
 		return (VMEXIT_ABORT);
@@ -502,7 +499,7 @@ static vmexit_handler_t handler[VM_EXITC
 	[VM_EXITCODE_RDMSR]  = vmexit_rdmsr,
 	[VM_EXITCODE_WRMSR]  = vmexit_wrmsr,
 	[VM_EXITCODE_MTRAP]  = vmexit_mtrap,
-	[VM_EXITCODE_PAGING] = vmexit_paging,
+	[VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
 	[VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap,
 };
 


More information about the svn-src-projects mailing list