summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bhyve
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2014-07-21 02:39:17 +0000
committerjhb <jhb@FreeBSD.org>2014-07-21 02:39:17 +0000
commit888f6511e321556007cf471f691cb84d9a817237 (patch)
tree84ace0524c020288c47a07096fb6abcb1d3387d4 /usr.sbin/bhyve
parentd034cf40e56b09120dc35d432b7fdc536c54f6ec (diff)
downloadFreeBSD-src-888f6511e321556007cf471f691cb84d9a817237.zip
FreeBSD-src-888f6511e321556007cf471f691cb84d9a817237.tar.gz
MFC 263780,264516,265062,265101,265203,265364:
Add an ioctl to suspend a virtual machine (VM_SUSPEND). 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. This logic can be disabled via the tunable 'hw.vmm.halt_detection'.
Diffstat (limited to 'usr.sbin/bhyve')
-rw-r--r--usr.sbin/bhyve/bhyverun.c73
1 files changed, 53 insertions, 20 deletions
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index 1bd6a20..e662ca3 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -113,6 +113,7 @@ struct bhyvestats {
uint64_t cpu_switch_rotate;
uint64_t cpu_switch_direct;
int io_reset;
+ int io_poweroff;
} stats;
struct mt_vmm_info {
@@ -271,13 +272,6 @@ fbsdrun_deletecpu(struct vmctx *ctx, int vcpu)
}
static int
-vmexit_catch_reset(void)
-{
- stats.io_reset++;
- return (VMEXIT_RESET);
-}
-
-static int
vmexit_catch_inout(void)
{
return (VMEXIT_ABORT);
@@ -327,8 +321,10 @@ vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
case INOUT_OK:
return (VMEXIT_CONTINUE);
case INOUT_RESET:
+ stats.io_reset++;
return (VMEXIT_RESET);
case INOUT_POWEROFF:
+ stats.io_poweroff++;
return (VMEXIT_POWEROFF);
default:
fprintf(stderr, "Unhandled %s%c 0x%04x\n",
@@ -399,17 +395,6 @@ vmexit_spinup_ap(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
}
static int
-vmexit_spindown_cpu(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
-{
- int lastcpu;
-
- lastcpu = fbsdrun_deletecpu(ctx, *pvcpu);
- if (!lastcpu)
- pthread_exit(NULL);
- return (vmexit_catch_reset());
-}
-
-static int
vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
{
@@ -493,6 +478,45 @@ vmexit_inst_emul(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
return (VMEXIT_CONTINUE);
}
+static pthread_mutex_t resetcpu_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t resetcpu_cond = PTHREAD_COND_INITIALIZER;
+
+static int
+vmexit_suspend(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
+{
+ enum vm_suspend_how how;
+
+ how = vmexit->u.suspended.how;
+
+ fbsdrun_deletecpu(ctx, *pvcpu);
+
+ if (*pvcpu != BSP) {
+ pthread_mutex_lock(&resetcpu_mtx);
+ pthread_cond_signal(&resetcpu_cond);
+ pthread_mutex_unlock(&resetcpu_mtx);
+ pthread_exit(NULL);
+ }
+
+ pthread_mutex_lock(&resetcpu_mtx);
+ while (!CPU_EMPTY(&cpumask)) {
+ pthread_cond_wait(&resetcpu_cond, &resetcpu_mtx);
+ }
+ pthread_mutex_unlock(&resetcpu_mtx);
+
+ switch (how) {
+ case VM_SUSPEND_RESET:
+ exit(0);
+ 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 */
+}
+
static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
[VM_EXITCODE_INOUT] = vmexit_inout,
[VM_EXITCODE_VMX] = vmexit_vmx,
@@ -502,7 +526,7 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
[VM_EXITCODE_MTRAP] = vmexit_mtrap,
[VM_EXITCODE_INST_EMUL] = vmexit_inst_emul,
[VM_EXITCODE_SPINUP_AP] = vmexit_spinup_ap,
- [VM_EXITCODE_SPINDOWN_CPU] = vmexit_spindown_cpu,
+ [VM_EXITCODE_SUSPENDED] = vmexit_suspend
};
static void
@@ -510,6 +534,7 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip)
{
int error, rc, prevcpu;
enum vm_exitcode exitcode;
+ enum vm_suspend_how how;
if (vcpumap[vcpu] != NULL) {
error = pthread_setaffinity_np(pthread_self(),
@@ -541,7 +566,15 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t rip)
rip = vmexit[vcpu].rip;
break;
case VMEXIT_RESET:
- exit(0);
+ 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:
exit(1);
}
OpenPOWER on IntegriCloud