Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 28 Apr 2014 22:06:40 +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: r265062 - in head: lib/libvmmapi sys/amd64/include sys/amd64/vmm sys/amd64/vmm/intel usr.sbin/bhyve usr.sbin/bhyvectl
Message-ID:  <201404282206.s3SM6e6W066814@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: neel
Date: Mon Apr 28 22:06:40 2014
New Revision: 265062
URL: http://svnweb.freebsd.org/changeset/base/265062

Log:
  Allow a virtual machine to be forcibly reset or powered off. This is done
  by adding an argument to the VM_SUSPEND ioctl that specifies how the virtual
  machine should be suspended, viz. VM_SUSPEND_RESET or VM_SUSPEND_POWEROFF.
  
  The disposition of VM_SUSPEND is also made available to the exit handler
  via the 'u.suspended' member of 'struct vm_exit'.
  
  This capability is exposed via the '--force-reset' and '--force-poweroff'
  arguments to /usr/sbin/bhyvectl.
  
  Discussed with:	grehan@

Modified:
  head/lib/libvmmapi/vmmapi.c
  head/lib/libvmmapi/vmmapi.h
  head/sys/amd64/include/vmm.h
  head/sys/amd64/include/vmm_dev.h
  head/sys/amd64/vmm/intel/vmx.c
  head/sys/amd64/vmm/vmm.c
  head/sys/amd64/vmm/vmm_dev.c
  head/usr.sbin/bhyve/bhyverun.c
  head/usr.sbin/bhyvectl/bhyvectl.c

Modified: head/lib/libvmmapi/vmmapi.c
==============================================================================
--- head/lib/libvmmapi/vmmapi.c	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/lib/libvmmapi/vmmapi.c	Mon Apr 28 22:06:40 2014	(r265062)
@@ -343,10 +343,13 @@ vm_run(struct vmctx *ctx, int vcpu, uint
 }
 
 int
-vm_suspend(struct vmctx *ctx)
+vm_suspend(struct vmctx *ctx, enum vm_suspend_how how)
 {
+	struct vm_suspend vmsuspend;
 
-	return (ioctl(ctx->fd, VM_SUSPEND, 0));
+	bzero(&vmsuspend, sizeof(vmsuspend));
+	vmsuspend.how = how;
+	return (ioctl(ctx->fd, VM_SUSPEND, &vmsuspend));
 }
 
 static int

Modified: head/lib/libvmmapi/vmmapi.h
==============================================================================
--- head/lib/libvmmapi/vmmapi.h	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/lib/libvmmapi/vmmapi.h	Mon Apr 28 22:06:40 2014	(r265062)
@@ -61,7 +61,7 @@ int	vm_set_register(struct vmctx *ctx, i
 int	vm_get_register(struct vmctx *ctx, int vcpu, int reg, uint64_t *retval);
 int	vm_run(struct vmctx *ctx, int vcpu, uint64_t rip,
 	       struct vm_exit *ret_vmexit);
-int	vm_suspend(struct vmctx *ctx);
+int	vm_suspend(struct vmctx *ctx, enum vm_suspend_how how);
 int	vm_apicid2vcpu(struct vmctx *ctx, int apicid);
 int	vm_inject_exception(struct vmctx *ctx, int vcpu, int vec);
 int	vm_inject_exception2(struct vmctx *ctx, int vcpu, int vec, int errcode);

Modified: head/sys/amd64/include/vmm.h
==============================================================================
--- head/sys/amd64/include/vmm.h	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/sys/amd64/include/vmm.h	Mon Apr 28 22:06:40 2014	(r265062)
@@ -29,6 +29,13 @@
 #ifndef _VMM_H_
 #define	_VMM_H_
 
+enum vm_suspend_how {
+	VM_SUSPEND_NONE,
+	VM_SUSPEND_RESET,
+	VM_SUSPEND_POWEROFF,
+	VM_SUSPEND_LAST
+};
+
 #ifdef _KERNEL
 
 #define	VM_MAX_NAMELEN	32
@@ -115,7 +122,7 @@ int vm_get_seg_desc(struct vm *vm, int v
 int vm_set_seg_desc(struct vm *vm, int vcpu, int reg,
 		    struct seg_desc *desc);
 int vm_run(struct vm *vm, struct vm_run *vmrun);
-int vm_suspend(struct vm *vm);
+int vm_suspend(struct vm *vm, enum vm_suspend_how how);
 int vm_inject_nmi(struct vm *vm, int vcpu);
 int vm_nmi_pending(struct vm *vm, int vcpuid);
 void vm_nmi_clear(struct vm *vm, int vcpuid);
@@ -134,6 +141,7 @@ int vm_apicid2vcpuid(struct vm *vm, int 
 void vm_activate_cpu(struct vm *vm, int vcpu);
 cpuset_t vm_active_cpus(struct vm *vm);
 struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid);
+void vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip);
 
 /*
  * Rendezvous all vcpus specified in 'dest' and execute 'func(arg)'.
@@ -382,6 +390,9 @@ struct vm_exit {
 		struct {
 			int		vector;
 		} ioapic_eoi;
+		struct {
+			enum vm_suspend_how how;
+		} suspended;
 	} u;
 };
 

Modified: head/sys/amd64/include/vmm_dev.h
==============================================================================
--- head/sys/amd64/include/vmm_dev.h	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/sys/amd64/include/vmm_dev.h	Mon Apr 28 22:06:40 2014	(r265062)
@@ -159,6 +159,10 @@ struct vm_hpet_cap {
 	uint32_t	capabilities;	/* lower 32 bits of HPET capabilities */
 };
 
+struct vm_suspend {
+	enum vm_suspend_how how;
+};
+
 enum {
 	/* general routines */
 	IOCNUM_ABIVERS = 0,
@@ -214,7 +218,7 @@ enum {
 #define	VM_RUN		\
 	_IOWR('v', IOCNUM_RUN, struct vm_run)
 #define	VM_SUSPEND	\
-	_IO('v', IOCNUM_SUSPEND)
+	_IOW('v', IOCNUM_SUSPEND, struct vm_suspend)
 #define	VM_MAP_MEMORY	\
 	_IOWR('v', IOCNUM_MAP_MEMORY, struct vm_memory_segment)
 #define	VM_GET_MEMORY_SEG \

Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/sys/amd64/vmm/intel/vmx.c	Mon Apr 28 22:06:40 2014	(r265062)
@@ -2045,16 +2045,6 @@ vmx_exit_rendezvous(struct vmx *vmx, int
 }
 
 static __inline int
-vmx_exit_suspended(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
-{
-
-	vmexit->rip = vmcs_guest_rip();
-	vmexit->inst_length = 0;
-	vmexit->exitcode = VM_EXITCODE_SUSPENDED;
-	return (UNHANDLED);
-}
-
-static __inline int
 vmx_exit_inst_error(struct vmxctx *vmxctx, int rc, struct vm_exit *vmexit)
 {
 
@@ -2173,7 +2163,8 @@ vmx_run(void *arg, int vcpu, register_t 
 		disable_intr();
 		if (vcpu_suspended(suspend_cookie)) {
 			enable_intr();
-			handled = vmx_exit_suspended(vmx, vcpu, vmexit);
+			vm_exit_suspended(vmx->vm, vcpu, vmcs_guest_rip());
+			handled = UNHANDLED;
 			break;
 		}
 

Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/sys/amd64/vmm/vmm.c	Mon Apr 28 22:06:40 2014	(r265062)
@@ -1211,16 +1211,45 @@ vm_handle_suspend(struct vm *vm, int vcp
 }
 
 int
-vm_suspend(struct vm *vm)
+vm_suspend(struct vm *vm, enum vm_suspend_how how)
 {
+	int i;
 
-	if (atomic_cmpset_int(&vm->suspend, 0, 1)) {
-		VM_CTR0(vm, "virtual machine suspended");
-		return (0);
-	} else {
-		VM_CTR0(vm, "virtual machine already suspended");
+	if (how <= VM_SUSPEND_NONE || how >= VM_SUSPEND_LAST)
+		return (EINVAL);
+
+	if (atomic_cmpset_int(&vm->suspend, 0, how) == 0) {
+		VM_CTR2(vm, "virtual machine already suspended %d/%d",
+		    vm->suspend, how);
 		return (EALREADY);
 	}
+
+	VM_CTR1(vm, "virtual machine successfully suspended %d", how);
+
+	/*
+	 * Notify all active vcpus that they are now suspended.
+	 */
+	for (i = 0; i < VM_MAXCPU; i++) {
+		if (CPU_ISSET(i, &vm->active_cpus))
+			vcpu_notify_event(vm, i, false);
+	}
+
+	return (0);
+}
+
+void
+vm_exit_suspended(struct vm *vm, int vcpuid, uint64_t rip)
+{
+	struct vm_exit *vmexit;
+
+	KASSERT(vm->suspend > VM_SUSPEND_NONE && vm->suspend < VM_SUSPEND_LAST,
+	    ("vm_exit_suspended: invalid suspend type %d", vm->suspend));
+
+	vmexit = vm_exitinfo(vm, vcpuid);
+	vmexit->rip = rip;
+	vmexit->inst_length = 0;
+	vmexit->exitcode = VM_EXITCODE_SUSPENDED;
+	vmexit->u.suspended.how = vm->suspend;
 }
 
 int

Modified: head/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- head/sys/amd64/vmm/vmm_dev.c	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/sys/amd64/vmm/vmm_dev.c	Mon Apr 28 22:06:40 2014	(r265062)
@@ -166,6 +166,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long c
 	struct vm_stat_desc *statdesc;
 	struct vm_x2apic *x2apic;
 	struct vm_gpa_pte *gpapte;
+	struct vm_suspend *vmsuspend;
 
 	sc = vmmdev_lookup2(cdev);
 	if (sc == NULL)
@@ -241,7 +242,8 @@ vmmdev_ioctl(struct cdev *cdev, u_long c
 		error = vm_run(sc->vm, vmrun);
 		break;
 	case VM_SUSPEND:
-		error = vm_suspend(sc->vm);
+		vmsuspend = (struct vm_suspend *)data;
+		error = vm_suspend(sc->vm, vmsuspend->how);
 		break;
 	case VM_STAT_DESC: {
 		statdesc = (struct vm_stat_desc *)data;

Modified: head/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- head/usr.sbin/bhyve/bhyverun.c	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/usr.sbin/bhyve/bhyverun.c	Mon Apr 28 22:06:40 2014	(r265062)
@@ -461,17 +461,18 @@ vmexit_inst_emul(struct vmctx *ctx, stru
 
 static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER;
-static int resetcpu = -1;
 
 static int
 vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
 {
-	
-	assert(resetcpu != -1);
+	enum vm_suspend_how how;
+
+	how = vmexit->u.suspended.how;
+	assert(how == VM_SUSPEND_RESET || how == VM_SUSPEND_POWEROFF);
 
 	fbsdrun_deletecpu(ctx, *pvcpu);
 
-	if (*pvcpu != resetcpu) {
+	if (*pvcpu != BSP) {
 		pthread_mutex_lock(&resetcpu_mtx);
 		pthread_cond_signal(&resetcpu_cond);
 		pthread_mutex_unlock(&resetcpu_mtx);
@@ -483,7 +484,12 @@ vmexit_suspend(struct vmctx *ctx, struct
 		pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx);
 	}
 	pthread_mutex_unlock(&resetcpu_mtx);
-	exit(0);
+
+	if (how == VM_SUSPEND_RESET)
+		exit(0);
+	if (how == VM_SUSPEND_POWEROFF)
+		exit(1);
+	return (0);	/* NOTREACHED */
 }
 
 static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
@@ -505,6 +511,7 @@ vm_loop(struct vmctx *ctx, int vcpu, uin
 	cpuset_t mask;
 	int error, rc, prevcpu;
 	enum vm_exitcode exitcode;
+	enum vm_suspend_how how;
 
 	if (pincpu >= 0) {
 		CPU_ZERO(&mask);
@@ -538,10 +545,13 @@ vm_loop(struct vmctx *ctx, int vcpu, uin
                         rip = vmexit[vcpu].rip;
 			break;
 		case VMEXIT_RESET:
-			if (vm_suspend(ctx) == 0) {
-				assert(resetcpu == -1);
-				resetcpu = vcpu;
-			}
+		case VMEXIT_POWEROFF:
+			if (rc == VMEXIT_RESET)
+				how = VM_SUSPEND_RESET;
+			else
+				how = VM_SUSPEND_POWEROFF;
+			error = vm_suspend(ctx, how);
+			assert(error == 0 || errno == EALREADY);
                         rip = vmexit[vcpu].rip + vmexit[vcpu].inst_length;
 			break;
 		default:

Modified: head/usr.sbin/bhyvectl/bhyvectl.c
==============================================================================
--- head/usr.sbin/bhyvectl/bhyvectl.c	Mon Apr 28 20:40:36 2014	(r265061)
+++ head/usr.sbin/bhyvectl/bhyvectl.c	Mon Apr 28 22:06:40 2014	(r265062)
@@ -191,13 +191,16 @@ usage(void)
 	"       [--get-highmem]\n"
 	"       [--get-gpa-pmap]\n"
 	"       [--assert-lapic-lvt=<pin>]\n"
-	"       [--inject-nmi]\n",
+	"       [--inject-nmi]\n"
+	"       [--force-reset]\n"
+	"       [--force-poweroff]\n",
 	progname);
 	exit(1);
 }
 
 static int get_stats, getcap, setcap, capval, get_gpa_pmap;
 static int inject_nmi, assert_lapic_lvt;
+static int force_reset, force_poweroff;
 static const char *capname;
 static int create, destroy, get_lowmem, get_highmem;
 static uint64_t memsize;
@@ -565,6 +568,8 @@ main(int argc, char *argv[])
 		{ "create",	NO_ARG,		&create,	1 },
 		{ "destroy",	NO_ARG,		&destroy,	1 },
 		{ "inject-nmi",	NO_ARG,		&inject_nmi,	1 },
+		{ "force-reset",	NO_ARG,	&force_reset,	1 },
+		{ "force-poweroff", NO_ARG,	&force_poweroff, 1 },
 		{ NULL,		0,		NULL,		0 }
 	};
 
@@ -1535,6 +1540,12 @@ main(int argc, char *argv[])
 			printf("vm_run error %d\n", error);
 	}
 
+	if (!error && force_reset)
+		error = vm_suspend(ctx, VM_SUSPEND_RESET);
+
+	if (!error && force_poweroff)
+		error = vm_suspend(ctx, VM_SUSPEND_POWEROFF);
+
 	if (error)
 		printf("errno = %d\n", errno);
 



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