From owner-svn-src-head@FreeBSD.ORG Mon Apr 28 22:06:42 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 587B74CB; Mon, 28 Apr 2014 22:06:42 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 390A61789; Mon, 28 Apr 2014 22:06:42 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s3SM6g48066826; Mon, 28 Apr 2014 22:06:42 GMT (envelope-from neel@svn.freebsd.org) Received: (from neel@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s3SM6e6W066814; Mon, 28 Apr 2014 22:06:40 GMT (envelope-from neel@svn.freebsd.org) Message-Id: <201404282206.s3SM6e6W066814@svn.freebsd.org> From: Neel Natu Date: Mon, 28 Apr 2014 22:06:40 +0000 (UTC) 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 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Apr 2014 22:06:42 -0000 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=]\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);