svn commit: r253133 - projects/bhyve_npt_pmap/sys/amd64/vmm

Neel Natu neel at FreeBSD.org
Wed Jul 10 04:59:11 UTC 2013


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

Log:
  Tidy up the vm_run() function by splitting the in-kernel handling of guest
  'hlt' and 'paging' vm exits into separate functions.

Modified:
  projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c

Modified: projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c
==============================================================================
--- projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c	Wed Jul 10 04:51:07 2013	(r253132)
+++ projects/bhyve_npt_pmap/sys/amd64/vmm/vmm.c	Wed Jul 10 04:59:10 2013	(r253133)
@@ -665,14 +665,106 @@ vcpu_require_state_locked(struct vcpu *v
 		panic("Error %d setting state to %d", error, newstate);
 }
 
+/*
+ * 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)
+{
+	struct vcpu *vcpu;
+	int sleepticks, t;
+
+	vcpu = &vm->vcpu[vcpuid];
+
+	vcpu_lock(vcpu);
+
+	/*
+	 * Figure out the number of host ticks until the next apic
+	 * timer interrupt in the guest.
+	 */
+	sleepticks = lapic_timer_tick(vm, vcpuid);
+
+	/*
+	 * If the guest local apic timer is disabled then sleep for
+	 * a long time but not forever.
+	 */
+	if (sleepticks < 0)
+		sleepticks = hz;
+
+	/*
+	 * Do a final check for pending NMI or interrupts before
+	 * really putting this thread to sleep.
+	 *
+	 * These interrupts could have happened any time after we
+	 * returned from VMRUN() and before we grabbed the vcpu lock.
+	 */
+	if (!vm_nmi_pending(vm, vcpuid) && lapic_pending_intr(vm, vcpuid) < 0) {
+		if (sleepticks <= 0)
+			panic("invalid sleepticks %d", sleepticks);
+		t = ticks;
+		vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
+		msleep_spin(vcpu, &vcpu->mtx, "vmidle", sleepticks);
+		vcpu_require_state_locked(vcpu, VCPU_FROZEN);
+		vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);
+	}
+	vcpu_unlock(vcpu);
+
+	return (0);
+}
+
+static int
+vcpu_paging(struct vm *vm, int vcpuid, boolean_t *retu)
+{
+	int rv;
+	struct thread *td;
+	struct proc *p;
+	struct vm_map *map;
+	vm_prot_t ftype;
+	struct vcpu *vcpu;
+	struct vm_exit *vme;
+
+	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;
+	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)
+		return (EFAULT);
+
+	/* restart execution at the faulting instruction */
+	vme->inst_length = 0;
+
+	return (0);
+}
+
 int
 vm_run(struct vm *vm, struct vm_run *vmrun)
 {
-	int error, vcpuid, sleepticks, t;
+	int error, vcpuid;
 	struct vcpu *vcpu;
 	struct pcb *pcb;
 	uint64_t tscval, rip;
 	struct vm_exit *vme;
+	boolean_t retu;
 
 	vcpuid = vmrun->cpuid;
 
@@ -706,89 +798,28 @@ restart:
 
 	critical_exit();
 
-	if (error)
-		goto done;
-
-	/*
-	 * Oblige the guest's desire to 'hlt' by sleeping until the vcpu
-	 * is ready to run.
-	 */
-	if (vme->exitcode == VM_EXITCODE_HLT) {
-		vcpu_lock(vcpu);
-
-		/*
-		 * Figure out the number of host ticks until the next apic
-		 * timer interrupt in the guest.
-		 */
-		sleepticks = lapic_timer_tick(vm, vcpuid);
-
-		/*
-		 * If the guest local apic timer is disabled then sleep for
-		 * a long time but not forever.
-		 */
-		if (sleepticks < 0)
-			sleepticks = hz;
-
-		/*
-		 * Do a final check for pending NMI or interrupts before
-		 * really putting this thread to sleep.
-		 *
-		 * These interrupts could have happened any time after we
-		 * returned from VMRUN() and before we grabbed the vcpu lock.
-		 */
-		if (!vm_nmi_pending(vm, vcpuid) &&
-		    lapic_pending_intr(vm, vcpuid) < 0) {
-			if (sleepticks <= 0)
-				panic("invalid sleepticks %d", sleepticks);
-			t = ticks;
-			vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
-			msleep_spin(vcpu, &vcpu->mtx, "vmidle", sleepticks);
-			vcpu_require_state_locked(vcpu, VCPU_FROZEN);
-			vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);
+	if (error == 0) {
+		retu = FALSE;
+		switch (vme->exitcode) {
+		case VM_EXITCODE_HLT:
+			error = vcpu_sleep(vm, vcpuid, &retu);
+			break;
+		case VM_EXITCODE_PAGING:
+			error = vcpu_paging(vm, vcpuid, &retu);
+			break;
+		default:
+			retu = TRUE;	/* handled in userland */
+			break;
 		}
+	}
 
-		vcpu_unlock(vcpu);
-
+	if (error == 0 && retu == FALSE) {
 		rip = vme->rip + vme->inst_length;
 		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 {
-			error = EFAULT;
-			goto done;
-		}
-	}
-
-done:
 	/* copy the exit information */
 	bcopy(vme, &vmrun->vm_exit, sizeof(struct vm_exit));
-
 	return (error);
 }
 


More information about the svn-src-projects mailing list