summaryrefslogtreecommitdiffstats
path: root/usr.sbin/vmd
diff options
context:
space:
mode:
authorpd <pd@openbsd.org>2017-07-09 00:51:40 +0000
committerpd <pd@openbsd.org>2017-07-09 00:51:40 +0000
commit52e954a3fad37facf0321bc5eab1a89fc28f90a7 (patch)
tree2d9d19d0ecc85e98b1b7cb5695ca0e63dc20e8ca /usr.sbin/vmd
parentthis program was infected with lint era casts. i think we're past that now. (diff)
downloadwireguard-openbsd-52e954a3fad37facf0321bc5eab1a89fc28f90a7.tar.xz
wireguard-openbsd-52e954a3fad37facf0321bc5eab1a89fc28f90a7.zip
vmd/vmctl: Add ability to pause / unpause vms
With help from Ashwin Agrawal ok reyk@ mlarkin@
Diffstat (limited to 'usr.sbin/vmd')
-rw-r--r--usr.sbin/vmd/control.c6
-rw-r--r--usr.sbin/vmd/i8253.c36
-rw-r--r--usr.sbin/vmd/i8253.h4
-rw-r--r--usr.sbin/vmd/mc146818.c12
-rw-r--r--usr.sbin/vmd/mc146818.h3
-rw-r--r--usr.sbin/vmd/vm.c89
-rw-r--r--usr.sbin/vmd/vmd.c43
-rw-r--r--usr.sbin/vmd/vmd.h7
-rw-r--r--usr.sbin/vmd/vmm.c45
9 files changed, 211 insertions, 34 deletions
diff --git a/usr.sbin/vmd/control.c b/usr.sbin/vmd/control.c
index 1e7eba2f0b3..08baa77cf0d 100644
--- a/usr.sbin/vmd/control.c
+++ b/usr.sbin/vmd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.19 2017/05/04 19:41:58 reyk Exp $ */
+/* $OpenBSD: control.c,v 1.20 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2010-2015 Reyk Floeter <reyk@openbsd.org>
@@ -83,6 +83,8 @@ control_dispatch_vmd(int fd, struct privsep_proc *p, struct imsg *imsg)
switch (imsg->hdr.type) {
case IMSG_VMDOP_START_VM_RESPONSE:
+ case IMSG_VMDOP_PAUSE_VM_RESPONSE:
+ case IMSG_VMDOP_UNPAUSE_VM_RESPONSE:
case IMSG_VMDOP_TERMINATE_VM_RESPONSE:
case IMSG_VMDOP_GET_INFO_VM_DATA:
case IMSG_VMDOP_GET_INFO_VM_END_DATA:
@@ -366,6 +368,8 @@ control_dispatch_imsg(int fd, short event, void *arg)
log_setverbose(v);
/* FALLTHROUGH */
+ case IMSG_VMDOP_PAUSE_VM:
+ case IMSG_VMDOP_UNPAUSE_VM:
case IMSG_VMDOP_LOAD:
case IMSG_VMDOP_RELOAD:
case IMSG_CTL_RESET:
diff --git a/usr.sbin/vmd/i8253.c b/usr.sbin/vmd/i8253.c
index 5fa4d8a34da..ff33c0ecae2 100644
--- a/usr.sbin/vmd/i8253.c
+++ b/usr.sbin/vmd/i8253.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i8253.c,v 1.15 2017/05/08 09:08:40 reyk Exp $ */
+/* $OpenBSD: i8253.c,v 1.16 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2016 Mike Larkin <mlarkin@openbsd.org>
*
@@ -314,6 +314,7 @@ i8253_reset(uint8_t chn)
evtimer_del(&i8253_channel[chn].timer);
timerclear(&tv);
+ i8253_channel[chn].in_use = 1;
tv.tv_usec = (i8253_channel[chn].start * NS_PER_TICK) / 1000;
evtimer_add(&i8253_channel[chn].timer, &tv);
}
@@ -359,30 +360,37 @@ i8253_dump(int fd)
int
i8253_restore(int fd, uint32_t vm_id)
{
+ int i;
log_debug("%s: restoring PIT", __func__);
if (atomicio(read, fd, &i8253_channel, sizeof(i8253_channel)) !=
sizeof(i8253_channel)) {
log_warnx("%s: error reading PIT from fd", __func__);
return (-1);
}
- memset(&i8253_channel[0].timer, 0, sizeof(struct event));
- memset(&i8253_channel[1].timer, 0, sizeof(struct event));
- memset(&i8253_channel[2].timer, 0, sizeof(struct event));
- i8253_channel[0].vm_id = vm_id;
- i8253_channel[1].vm_id = vm_id;
- i8253_channel[2].vm_id = vm_id;
- evtimer_set(&i8253_channel[0].timer, i8253_fire, &i8253_channel[0]);
- evtimer_set(&i8253_channel[1].timer, i8253_fire, &i8253_channel[1]);
- evtimer_set(&i8253_channel[2].timer, i8253_fire, &i8253_channel[2]);
- i8253_reset(0);
+ for (i = 0; i < 3; i++) {
+ memset(&i8253_channel[i].timer, 0, sizeof(struct event));
+ i8253_channel[i].vm_id = vm_id;
+ evtimer_set(&i8253_channel[i].timer, i8253_fire,
+ &i8253_channel[i]);
+ i8253_reset(i);
+ }
return (0);
}
void
i8253_stop()
{
- evtimer_del(&i8253_channel[0].timer);
- evtimer_del(&i8253_channel[1].timer);
- evtimer_del(&i8253_channel[2].timer);
+ int i;
+ for (i = 0; i < 3; i++)
+ evtimer_del(&i8253_channel[i].timer);
+}
+
+void
+i8253_start()
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ if(i8253_channel[i].in_use)
+ i8253_reset(i);
}
diff --git a/usr.sbin/vmd/i8253.h b/usr.sbin/vmd/i8253.h
index 2bd6de8eef7..564dc5c5938 100644
--- a/usr.sbin/vmd/i8253.h
+++ b/usr.sbin/vmd/i8253.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: i8253.h,v 1.6 2017/05/08 09:08:40 reyk Exp $ */
+/* $OpenBSD: i8253.h,v 1.7 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2016 Mike Larkin <mlarkin@openbsd.org>
*
@@ -39,6 +39,7 @@ struct i8253_channel {
uint8_t rbs; /* channel is in readback status mode */
struct event timer; /* timer event for this counter */
uint32_t vm_id; /* owning VM id */
+ int in_use; /* denotes if this counter was ever used */
};
void i8253_init(uint32_t);
@@ -49,3 +50,4 @@ int i8253_restore(int, uint32_t);
uint8_t vcpu_exit_i8253(struct vm_run_params *);
void i8253_do_readback(uint32_t);
void i8253_stop(void);
+void i8253_start(void);
diff --git a/usr.sbin/vmd/mc146818.c b/usr.sbin/vmd/mc146818.c
index 66656959556..2a81f17f75d 100644
--- a/usr.sbin/vmd/mc146818.c
+++ b/usr.sbin/vmd/mc146818.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mc146818.c,v 1.14 2017/05/08 09:08:40 reyk Exp $ */
+/* $OpenBSD: mc146818.c,v 1.15 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2016 Mike Larkin <mlarkin@openbsd.org>
*
@@ -341,9 +341,6 @@ mc146818_restore(int fd, uint32_t vm_id)
memset(&rtc.per, 0, sizeof(struct event));
evtimer_set(&rtc.sec, rtc_fire1, NULL);
evtimer_set(&rtc.per, rtc_fireper, (void *)(intptr_t)rtc.vm_id);
-
- evtimer_add(&rtc.per, &rtc.per_tv);
- evtimer_add(&rtc.sec, &rtc.sec_tv);
return (0);
}
@@ -353,3 +350,10 @@ mc146818_stop()
evtimer_del(&rtc.per);
evtimer_del(&rtc.sec);
}
+
+void
+mc146818_start()
+{
+ evtimer_add(&rtc.per, &rtc.per_tv);
+ evtimer_add(&rtc.sec, &rtc.sec_tv);
+}
diff --git a/usr.sbin/vmd/mc146818.h b/usr.sbin/vmd/mc146818.h
index 8eadb47d0aa..f6e3509aa60 100644
--- a/usr.sbin/vmd/mc146818.h
+++ b/usr.sbin/vmd/mc146818.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mc146818.h,v 1.4 2017/05/08 09:08:40 reyk Exp $ */
+/* $OpenBSD: mc146818.h,v 1.5 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2016 Mike Larkin <mlarkin@openbsd.org>
*
@@ -21,3 +21,4 @@ void dump_mc146818(void);
int mc146818_dump(int);
int mc146818_restore(int, uint32_t);
void mc146818_stop(void);
+void mc146818_start(void);
diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c
index 1c4e354422b..87b980d269c 100644
--- a/usr.sbin/vmd/vm.c
+++ b/usr.sbin/vmd/vm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm.c,v 1.20 2017/06/07 14:53:28 mlarkin Exp $ */
+/* $OpenBSD: vm.c,v 1.21 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -77,6 +77,8 @@ void vcpu_exit_inout(struct vm_run_params *);
uint8_t vcpu_exit_pci(struct vm_run_params *);
int vcpu_pic_intr(uint32_t, uint32_t, uint8_t);
int loadfile_bios(FILE *, struct vcpu_reg_state *);
+void pause_vm(struct vm_create_params *);
+void unpause_vm(struct vm_create_params *);
static struct vm_mem_range *find_gpa_range(struct vm_create_params *, paddr_t,
size_t);
@@ -345,6 +347,7 @@ void
vm_dispatch_vmm(int fd, short event, void *arg)
{
struct vmd_vm *vm = arg;
+ struct vmop_result vmr;
struct imsgev *iev = &vm->vm_iev;
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
@@ -391,6 +394,24 @@ vm_dispatch_vmm(int fd, short event, void *arg)
if (vmmci_ctl(VMMCI_REBOOT) == -1)
_exit(0);
break;
+ case IMSG_VMDOP_PAUSE_VM:
+ vmr.vmr_result = 0;
+ vmr.vmr_id = vm->vm_vmid;
+ pause_vm(&vm->vm_params.vmc_params);
+ imsg_compose_event(&vm->vm_iev,
+ IMSG_VMDOP_PAUSE_VM_RESPONSE,
+ imsg.hdr.peerid, imsg.hdr.pid, -1, &vmr,
+ sizeof(vmr));
+ break;
+ case IMSG_VMDOP_UNPAUSE_VM:
+ vmr.vmr_result = 0;
+ vmr.vmr_id = vm->vm_vmid;
+ unpause_vm(&vm->vm_params.vmc_params);
+ imsg_compose_event(&vm->vm_iev,
+ IMSG_VMDOP_UNPAUSE_VM_RESPONSE,
+ imsg.hdr.peerid, imsg.hdr.pid, -1, &vmr,
+ sizeof(vmr));
+ break;
default:
fatalx("%s: got invalid imsg %d from %s",
__func__, imsg.hdr.type,
@@ -427,6 +448,37 @@ vm_shutdown(unsigned int cmd)
_exit(0);
}
+void
+pause_vm(struct vm_create_params *vcp)
+{
+ if (current_vm->vm_paused)
+ return;
+
+ current_vm->vm_paused = 1;
+
+ /* XXX: vcpu_run_loop is running in another thread and we have to wait
+ * for the vm to exit before returning */
+ sleep(1);
+
+ i8253_stop();
+ mc146818_stop();
+}
+
+void
+unpause_vm(struct vm_create_params *vcp)
+{
+ unsigned int n;
+ if (!current_vm->vm_paused)
+ return;
+
+ current_vm->vm_paused = 0;
+
+ i8253_start();
+ mc146818_start();
+ for (n = 0; n <= vcp->vcp_ncpus; n++)
+ pthread_cond_broadcast(&vcpu_run_cond[n]);
+}
+
/*
* vcpu_reset
*
@@ -921,20 +973,37 @@ vcpu_run_loop(void *arg)
return ((void *)ret);
}
- /* If we are halted, wait */
+ /* If we are halted or paused, wait */
if (vcpu_hlt[n]) {
- ret = pthread_cond_wait(&vcpu_run_cond[n],
- &vcpu_run_mtx[n]);
-
- if (ret) {
- log_warnx("%s: can't wait on cond (%d)",
- __func__, (int)ret);
- (void)pthread_mutex_unlock(&vcpu_run_mtx[n]);
- break;
+ while (current_vm->vm_paused == 1) {
+ ret = pthread_cond_wait(&vcpu_run_cond[n],
+ &vcpu_run_mtx[n]);
+ if (ret) {
+ log_warnx(
+ "%s: can't wait on cond (%d)",
+ __func__, (int)ret);
+ (void)pthread_mutex_unlock(
+ &vcpu_run_mtx[n]);
+ break;
+ }
+ }
+ if (vcpu_hlt[n]) {
+ ret = pthread_cond_wait(&vcpu_run_cond[n],
+ &vcpu_run_mtx[n]);
+
+ if (ret) {
+ log_warnx(
+ "%s: can't wait on cond (%d)",
+ __func__, (int)ret);
+ (void)pthread_mutex_unlock(
+ &vcpu_run_mtx[n]);
+ break;
+ }
}
}
ret = pthread_mutex_unlock(&vcpu_run_mtx[n]);
+
if (ret) {
log_warnx("%s: can't unlock mutex on cond (%d)",
__func__, (int)ret);
diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c
index 440d64f87de..ca332ae3f28 100644
--- a/usr.sbin/vmd/vmd.c
+++ b/usr.sbin/vmd/vmd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.c,v 1.62 2017/05/29 07:15:22 mlarkin Exp $ */
+/* $OpenBSD: vmd.c,v 1.63 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
@@ -163,6 +163,22 @@ vmd_dispatch_control(int fd, struct privsep_proc *p, struct imsg *imsg)
proc_forward_imsg(ps, imsg, PROC_PRIV, -1);
cmd = IMSG_CTL_OK;
break;
+ case IMSG_VMDOP_PAUSE_VM:
+ case IMSG_VMDOP_UNPAUSE_VM:
+ IMSG_SIZE_CHECK(imsg, &vid);
+ memcpy(&vid, imsg->data, sizeof(vid));
+ if (vid.vid_id == 0) {
+ if ((vm = vm_getbyname(vid.vid_name)) == NULL) {
+ res = ENOENT;
+ cmd = IMSG_VMDOP_PAUSE_VM_RESPONSE;
+ break;
+ } else {
+ vid.vid_id = vm->vm_vmid;
+ }
+ }
+ proc_compose_imsg(ps, PROC_VMM, -1, imsg->hdr.type,
+ imsg->hdr.peerid, -1, &vid, sizeof(vid));
+ break;
default:
return (-1);
}
@@ -200,6 +216,30 @@ vmd_dispatch_vmm(int fd, struct privsep_proc *p, struct imsg *imsg)
struct vmop_info_result vir;
switch (imsg->hdr.type) {
+ case IMSG_VMDOP_PAUSE_VM_RESPONSE:
+ IMSG_SIZE_CHECK(imsg, &vmr);
+ memcpy(&vmr, imsg->data, sizeof(vmr));
+ if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL)
+ break;
+ proc_compose_imsg(ps, PROC_CONTROL, -1,
+ imsg->hdr.type, imsg->hdr.peerid, -1,
+ imsg->data, sizeof(imsg->data));
+ log_info("%s: paused vm %d successfully",
+ vm->vm_params.vmc_params.vcp_name,
+ vm->vm_vmid);
+ break;
+ case IMSG_VMDOP_UNPAUSE_VM_RESPONSE:
+ IMSG_SIZE_CHECK(imsg, &vmr);
+ memcpy(&vmr, imsg->data, sizeof(vmr));
+ if ((vm = vm_getbyvmid(vmr.vmr_id)) == NULL)
+ break;
+ proc_compose_imsg(ps, PROC_CONTROL, -1,
+ imsg->hdr.type, imsg->hdr.peerid, -1,
+ imsg->data, sizeof(imsg->data));
+ log_info("%s: unpaused vm %d successfully.",
+ vm->vm_params.vmc_params.vcp_name,
+ vm->vm_vmid);
+ break;
case IMSG_VMDOP_START_VM_RESPONSE:
IMSG_SIZE_CHECK(imsg, &vmr);
memcpy(&vmr, imsg->data, sizeof(vmr));
@@ -869,6 +909,7 @@ vm_register(struct privsep *ps, struct vmop_create_params *vmc,
vcp = &vmc->vmc_params;
vm->vm_pid = -1;
vm->vm_tty = -1;
+ vm->vm_paused = 0;
for (i = 0; i < vcp->vcp_ndisks; i++)
vm->vm_disks[i] = -1;
diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h
index be621835eaa..0cfd4cf546c 100644
--- a/usr.sbin/vmd/vmd.h
+++ b/usr.sbin/vmd/vmd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmd.h,v 1.56 2017/06/12 13:41:24 deraadt Exp $ */
+/* $OpenBSD: vmd.h,v 1.57 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -65,6 +65,10 @@ enum imsg_type {
IMSG_VMDOP_START_VM_IF,
IMSG_VMDOP_START_VM_END,
IMSG_VMDOP_START_VM_RESPONSE,
+ IMSG_VMDOP_PAUSE_VM,
+ IMSG_VMDOP_PAUSE_VM_RESPONSE,
+ IMSG_VMDOP_UNPAUSE_VM,
+ IMSG_VMDOP_UNPAUSE_VM_RESPONSE,
IMSG_VMDOP_TERMINATE_VM_REQUEST,
IMSG_VMDOP_TERMINATE_VM_RESPONSE,
IMSG_VMDOP_TERMINATE_VM_EVENT,
@@ -189,6 +193,7 @@ struct vmd_vm {
struct imsgev vm_iev;
int vm_shutdown;
uid_t vm_uid;
+ int vm_paused;
TAILQ_ENTRY(vmd_vm) vm_entry;
};
diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c
index 3b0a453032b..2e992d6cb15 100644
--- a/usr.sbin/vmd/vmm.c
+++ b/usr.sbin/vmd/vmm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vmm.c,v 1.69 2017/04/21 07:03:26 reyk Exp $ */
+/* $OpenBSD: vmm.c,v 1.70 2017/07/09 00:51:40 pd Exp $ */
/*
* Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org>
@@ -105,6 +105,7 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
int res = 0, cmd = 0, verbose;
struct vmd_vm *vm = NULL;
struct vm_terminate_params vtp;
+ struct vmop_id vid;
struct vmop_result vmr;
uint32_t id = 0;
unsigned int mode;
@@ -202,6 +203,33 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
-1, &verbose, sizeof(verbose));
}
break;
+ case IMSG_VMDOP_PAUSE_VM:
+ IMSG_SIZE_CHECK(imsg, &vid);
+ memcpy(&vid, imsg->data, sizeof(vid));
+ id = vid.vid_id;
+ vm = vm_getbyvmid(id);
+ if ((vm = vm_getbyvmid(id)) == NULL) {
+ res = ENOENT;
+ cmd = IMSG_VMDOP_PAUSE_VM_RESPONSE;
+ break;
+ }
+ imsg_compose_event(&vm->vm_iev,
+ imsg->hdr.type, imsg->hdr.peerid, imsg->hdr.pid,
+ imsg->fd, &vid, sizeof(vid));
+ break;
+ case IMSG_VMDOP_UNPAUSE_VM:
+ IMSG_SIZE_CHECK(imsg, &vid);
+ memcpy(&vid, imsg->data, sizeof(vid));
+ id = vid.vid_id;
+ if ((vm = vm_getbyvmid(id)) == NULL) {
+ res = ENOENT;
+ cmd = IMSG_VMDOP_UNPAUSE_VM_RESPONSE;
+ break;
+ }
+ imsg_compose_event(&vm->vm_iev,
+ imsg->hdr.type, imsg->hdr.peerid, imsg->hdr.pid,
+ imsg->fd, &vid, sizeof(vid));
+ break;
default:
return (-1);
}
@@ -217,6 +245,8 @@ vmm_dispatch_parent(int fd, struct privsep_proc *p, struct imsg *imsg)
}
if (id == 0)
id = imsg->hdr.peerid;
+ case IMSG_VMDOP_PAUSE_VM_RESPONSE:
+ case IMSG_VMDOP_UNPAUSE_VM_RESPONSE:
case IMSG_VMDOP_TERMINATE_VM_RESPONSE:
memset(&vmr, 0, sizeof(vmr));
vmr.vmr_result = res;
@@ -354,6 +384,7 @@ vmm_dispatch_vm(int fd, short event, void *arg)
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
ssize_t n;
+ unsigned int i;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
@@ -392,6 +423,18 @@ vmm_dispatch_vm(int fd, short event, void *arg)
case IMSG_VMDOP_VM_REBOOT:
vm->vm_shutdown = 0;
break;
+ case IMSG_VMDOP_PAUSE_VM_RESPONSE:
+ case IMSG_VMDOP_UNPAUSE_VM_RESPONSE:
+ for (i = 0; i < sizeof(procs); i++) {
+ if (procs[i].p_id == PROC_PARENT) {
+ proc_forward_imsg(procs[i].p_ps,
+ &imsg, PROC_PARENT,
+ -1);
+ break;
+ }
+ }
+ break;
+
default:
fatalx("%s: got invalid imsg %d from %s",
__func__, imsg.hdr.type,