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

Neel Natu neel at FreeBSD.org
Mon Jul 8 19:40:52 UTC 2013


Author: neel
Date: Mon Jul  8 19:40:50 2013
New Revision: 253044
URL: http://svnweb.freebsd.org/changeset/base/253044

Log:
  Fault in guest memory in response to EPT faults.
  
  The EPT faults are distinguished as follows:
  
  - Faults that point to an address that is assigned to a "memory" region
    will be resolved using vm_fault()
  
  - All other EPT faults are resolved via instruction emulation under the
    assumption that they happened because of an instruction accessing MMIO.

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/usr.sbin/bhyve/bhyverun.c

Modified: projects/bhyve_npt_pmap/sys/amd64/include/vmm.h
==============================================================================
--- projects/bhyve_npt_pmap/sys/amd64/include/vmm.h	Mon Jul  8 19:19:29 2013	(r253043)
+++ projects/bhyve_npt_pmap/sys/amd64/include/vmm.h	Mon Jul  8 19:40:50 2013	(r253044)
@@ -98,6 +98,7 @@ int vm_gpabase2memseg(struct vm *vm, vm_
 	      struct vm_memory_segment *seg);
 int vm_get_memobj(struct vm *vm, vm_paddr_t gpa, size_t len,
 		  vm_offset_t *offset, struct vm_object **object);
+boolean_t vm_mem_allocated(struct vm *vm, vm_paddr_t gpa);
 int vm_get_register(struct vm *vm, int vcpu, int reg, uint64_t *retval);
 int vm_set_register(struct vm *vm, int vcpu, int reg, uint64_t val);
 int vm_get_seg_desc(struct vm *vm, int vcpu, int reg,
@@ -269,6 +270,8 @@ struct vm_exit {
 		struct {
 			uint64_t	gpa;
 			struct vie	vie;
+			int		inst_emulation;
+			int		fault_type;
 		} paging;
 		/*
 		 * VMX specific payload. Used when there is no "better"

Modified: projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c	Mon Jul  8 19:19:29 2013	(r253043)
+++ projects/bhyve_npt_pmap/sys/amd64/vmm/intel/vmx.c	Mon Jul  8 19:40:50 2013	(r253044)
@@ -1175,7 +1175,22 @@ vmx_emulate_cr_access(struct vmx *vmx, i
 }
 
 static int
-vmx_ept_fault(struct vm *vm, int cpu,
+ept_fault_type(uint64_t ept_qual)
+{
+	int fault_type = 0;
+
+	if (ept_qual & EPT_VIOLATION_INST_FETCH)
+		fault_type |= VM_PROT_EXECUTE;
+	if (ept_qual & EPT_VIOLATION_DATA_READ)
+		fault_type |= VM_PROT_READ;
+	if (ept_qual & EPT_VIOLATION_DATA_WRITE)
+		fault_type |= VM_PROT_WRITE;
+
+	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)
 {
@@ -1223,7 +1238,7 @@ vmx_ept_fault(struct vm *vm, int cpu,
 static int
 vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
 {
-	int error, handled;
+	int error, handled, emulation;
 	struct vmcs *vmcs;
 	struct vmxctx *vmxctx;
 	uint32_t eax, ecx, edx;
@@ -1334,15 +1349,30 @@ vmx_exit_process(struct vmx *vmx, int vc
 		break;
 	case EXIT_REASON_EPT_FAULT:
 		vmm_stat_incr(vmx->vm, vcpu, VMEXIT_EPT_FAULT, 1);
-		gla = vmcs_gla();
+		/*
+		 * If 'gpa' lies within the address space allocated to
+		 * memory then this must be a nested page fault otherwise
+		 * this must be an instruction that accesses MMIO space.
+		 */
 		gpa = vmcs_gpa();
-		cr3 = vmcs_guest_cr3();
-		handled = vmx_ept_fault(vmx->vm, vcpu, gla, gpa,
-					vmexit->rip, vmexit->inst_length,
-					cr3, qual, &vmexit->u.paging.vie);
+		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);
 		}
 		break;
 	default:

Modified: projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c
==============================================================================
--- projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c	Mon Jul  8 19:19:29 2013	(r253043)
+++ projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c	Mon Jul  8 19:40:50 2013	(r253044)
@@ -49,6 +49,8 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm_page.h>
 #include <vm/pmap.h>
 #include <vm/vm_map.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
 
 #include <machine/vm.h>
 #include <machine/pcb.h>
@@ -364,26 +366,20 @@ vm_unmap_mmio(struct vm *vm, vm_paddr_t 
 	return (ENXIO);		/* XXX fixme */
 }
 
-/*
- * Returns TRUE if 'gpa' is available for allocation and FALSE otherwise
- */
-static boolean_t
-vm_gpa_available(struct vm *vm, vm_paddr_t gpa)
+boolean_t
+vm_mem_allocated(struct vm *vm, vm_paddr_t gpa)
 {
 	int i;
 	vm_paddr_t gpabase, gpalimit;
 
-	if (gpa & PAGE_MASK)
-		panic("vm_gpa_available: gpa (0x%016lx) not page aligned", gpa);
-
 	for (i = 0; i < vm->num_mem_segs; i++) {
 		gpabase = vm->mem_segs[i].gpa;
 		gpalimit = gpabase + vm->mem_segs[i].len;
 		if (gpa >= gpabase && gpa < gpalimit)
-			return (FALSE);
+			return (TRUE);
 	}
 
-	return (TRUE);
+	return (FALSE);
 }
 
 /*
@@ -403,10 +399,10 @@ vm_malloc(struct vm *vm, vm_paddr_t gpa,
 	available = allocated = 0;
 	g = gpa;
 	while (g < gpa + len) {
-		if (vm_gpa_available(vm, g))
-			available++;
-		else
+		if (vm_mem_allocated(vm, g))
 			allocated++;
+		else
+			available++;
 
 		g += PAGE_SIZE;
 	}
@@ -657,11 +653,14 @@ restart:
 
 	critical_exit();
 
+	if (error)
+		goto done;
+
 	/*
 	 * Oblige the guest's desire to 'hlt' by sleeping until the vcpu
 	 * is ready to run.
 	 */
-	if (error == 0 && vme->exitcode == VM_EXITCODE_HLT) {
+	if (vme->exitcode == VM_EXITCODE_HLT) {
 		vcpu_lock(vcpu);
 
 		/*
@@ -699,6 +698,39 @@ restart:
 		goto restart;
 	}
 
+	if (vme->exitcode == VM_EXITCODE_PAGING &&
+	    vme->u.paging.inst_emulation == 0) {
+		int rv;
+		struct thread *td;
+		struct proc *p;
+		struct vm_map *map;
+		vm_prot_t ftype;
+
+		td = curthread;
+		p = td->td_proc;
+		map = &vm->vmspace->vm_map;
+		ftype = vme->u.paging.fault_type;
+
+		PROC_LOCK(p);
+		p->p_lock++;
+		PROC_UNLOCK(p);
+
+		rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL);
+
+		PROC_LOCK(p);
+		p->p_lock--;
+		PROC_UNLOCK(p);
+
+		if (rv == KERN_SUCCESS) {
+			rip = vme->rip;
+			goto restart;
+		} else {
+			/* XXX */
+			vme->inst_length = 0;
+		}
+	}
+
+done:
 	return (error);
 }
 

Modified: projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c	Mon Jul  8 19:19:29 2013	(r253043)
+++ projects/bhyve_npt_pmap/usr.sbin/bhyve/bhyverun.c	Mon Jul  8 19:40:50 2013	(r253044)
@@ -440,8 +440,11 @@ vmexit_paging(struct vmctx *ctx, struct 
 	int err;
 	stats.vmexit_paging++;
 
-	err = emulate_mem(ctx, *pvcpu, vmexit->u.paging.gpa,
-			  &vmexit->u.paging.vie);
+	if (vmexit->u.paging.inst_emulation) {
+		err = emulate_mem(ctx, *pvcpu, vmexit->u.paging.gpa,
+				  &vmexit->u.paging.vie);
+	} else
+		err = ESRCH;
 
 	if (err) {
 		if (err == EINVAL) {


More information about the svn-src-projects mailing list