Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 2 May 2014 00:33:56 +0000 (UTC)
From:      Neel Natu <neel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r265203 - in head: sys/amd64/include sys/amd64/vmm usr.sbin/bhyve
Message-ID:  <201405020033.s420Xu91035658@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: neel
Date: Fri May  2 00:33:56 2014
New Revision: 265203
URL: http://svnweb.freebsd.org/changeset/base/265203

Log:
  Add logic in the HLT exit handler to detect if the guest has put all vcpus
  to sleep permanently by executing a HLT with interrupts disabled.
  
  When this condition is detected the guest with be suspended with a reason of
  VM_SUSPEND_HALT and the bhyve(8) process will exit.
  
  Tested by executing "halt" inside a RHEL7-beta guest.
  
  Discussed with:	grehan@
  Reviewed by:	jhb@, tychon@

Modified:
  head/sys/amd64/include/vmm.h
  head/sys/amd64/vmm/vmm.c
  head/usr.sbin/bhyve/bhyverun.c

Modified: head/sys/amd64/include/vmm.h
==============================================================================
--- head/sys/amd64/include/vmm.h	Thu May  1 23:34:14 2014	(r265202)
+++ head/sys/amd64/include/vmm.h	Fri May  2 00:33:56 2014	(r265203)
@@ -33,6 +33,7 @@ enum vm_suspend_how {
 	VM_SUSPEND_NONE,
 	VM_SUSPEND_RESET,
 	VM_SUSPEND_POWEROFF,
+	VM_SUSPEND_HALT,
 	VM_SUSPEND_LAST
 };
 

Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c	Thu May  1 23:34:14 2014	(r265202)
+++ head/sys/amd64/vmm/vmm.c	Fri May  2 00:33:56 2014	(r265203)
@@ -142,6 +142,8 @@ struct vm {
 
 	int		suspend;
 	volatile cpuset_t suspended_cpus;
+
+	volatile cpuset_t halted_cpus;
 };
 
 static int vmm_initialized;
@@ -1006,9 +1008,13 @@ vm_handle_hlt(struct vm *vm, int vcpuid,
 {
 	struct vcpu *vcpu;
 	const char *wmesg;
-	int t;
+	int t, vcpu_halted, vm_halted;
+
+	KASSERT(!CPU_ISSET(vcpuid, &vm->halted_cpus), ("vcpu already halted"));
 
 	vcpu = &vm->vcpu[vcpuid];
+	vcpu_halted = 0;
+	vm_halted = 0;
 
 	vcpu_lock(vcpu);
 	while (1) {
@@ -1032,10 +1038,26 @@ vm_handle_hlt(struct vm *vm, int vcpuid,
 			}
 		}
 
-		if (vlapic_enabled(vcpu->vlapic))
-			wmesg = "vmidle";
-		else
+		/*
+		 * Some Linux guests implement "halt" by having all vcpus
+		 * execute HLT with interrupts disabled. 'halted_cpus' keeps
+		 * track of the vcpus that have entered this state. When all
+		 * vcpus enter the halted state the virtual machine is halted.
+		 */
+		if (intr_disabled) {
 			wmesg = "vmhalt";
+			VCPU_CTR0(vm, vcpuid, "Halted");
+			if (!vcpu_halted) {
+				vcpu_halted = 1;
+				CPU_SET_ATOMIC(vcpuid, &vm->halted_cpus);
+			}
+			if (CPU_CMP(&vm->halted_cpus, &vm->active_cpus) == 0) {
+				vm_halted = 1;
+				break;
+			}
+		} else {
+			wmesg = "vmidle";
+		}
 
 		t = ticks;
 		vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
@@ -1043,8 +1065,15 @@ vm_handle_hlt(struct vm *vm, int vcpuid,
 		vcpu_require_state_locked(vcpu, VCPU_FROZEN);
 		vmm_stat_incr(vm, vcpuid, VCPU_IDLE_TICKS, ticks - t);
 	}
+
+	if (vcpu_halted)
+		CPU_CLR_ATOMIC(vcpuid, &vm->halted_cpus);
+
 	vcpu_unlock(vcpu);
 
+	if (vm_halted)
+		vm_suspend(vm, VM_SUSPEND_HALT);
+
 	return (0);
 }
 

Modified: head/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- head/usr.sbin/bhyve/bhyverun.c	Thu May  1 23:34:14 2014	(r265202)
+++ head/usr.sbin/bhyve/bhyverun.c	Fri May  2 00:33:56 2014	(r265203)
@@ -453,7 +453,6 @@ vmexit_suspend(struct vmctx *ctx, struct
 	enum vm_suspend_how how;
 
 	how = vmexit->u.suspended.how;
-	assert(how == VM_SUSPEND_RESET || how == VM_SUSPEND_POWEROFF);
 
 	fbsdrun_deletecpu(ctx, *pvcpu);
 
@@ -470,10 +469,17 @@ vmexit_suspend(struct vmctx *ctx, struct
 	}
 	pthread_mutex_unlock(&resetcpu_mtx);
 
-	if (how == VM_SUSPEND_RESET)
+	switch (how) {
+	case VM_SUSPEND_RESET:
 		exit(0);
-	if (how == VM_SUSPEND_POWEROFF)
+	case VM_SUSPEND_POWEROFF:
 		exit(1);
+	case VM_SUSPEND_HALT:
+		exit(2);
+	default:
+		fprintf(stderr, "vmexit_suspend: invalid reason %d\n", how);
+		exit(100);
+	}
 	return (0);	/* NOTREACHED */
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405020033.s420Xu91035658>