* Reyk Floeter <r...@openbsd.org> [2017-05-05 18:11:22 +0200]:

Once again and for the record: nice work!

Thank you!

See comments below, otherwise OK.

Addressed and attached a patch inline.

(As mentioned before, we should try to merge this part if init and
restore later to make it easier to keep it in sync.)

The virtio_init() code also has the following line:

                        vionet[i].vm_vmid = vm->vm_vmid;

vm_vmid is the "vmd userspace id", vm_id is the "kernel id".  We use
the vm_vmid in the integrated bootp/dhcp server to calculate the IP
guest and host addresses for -L mode that is communicated to the VM.

The restored VM will most probably have a new vm_vmid, so you have to
update it as well.  We cannot keep the old one as it a) might not
match what is configured on the host side tap(4) interface via priv.c
and b) it might conflict with a different VM that is running on the
target host.

Now you have to pass vm->vm_vmid to the restore functions, but maybe
it is just easier to pass struct vmd_vm *vm instead of struct
vm_create_params *vcp to all restore_emulated_hw() functions, because
*vm includes the vcp and all other information.


Did this for vionet to be able to set vionet[i].vm_vmid for now. I do
think breaking out init and reusing parts of it code for restore is
a good idea and standardising vmd_vm can be part of the same exercise.
Will send a patch in future.

--
Pratik


Index: usr.sbin/vmd/Makefile
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/Makefile,v
retrieving revision 1.14
diff -u -p -a -u -r1.14 Makefile
--- usr.sbin/vmd/Makefile       19 Apr 2017 15:38:32 -0000      1.14
+++ usr.sbin/vmd/Makefile       6 May 2017 17:56:55 -0000
@@ -6,7 +6,7 @@ PROG=           vmd
SRCS=           vmd.c control.c log.c priv.c proc.c config.c vmm.c
SRCS+=          vm.c loadfile_elf.c pci.c virtio.c i8259.c mc146818.c
SRCS+=          ns8250.c i8253.c vmboot.c ufs.c disklabel.c dhcp.c packet.c
-SRCS+=         parse.y
+SRCS+=         parse.y atomicio.c

CFLAGS+=        -Wall -I${.CURDIR}
CFLAGS+=        -Wstrict-prototypes -Wmissing-prototypes
Index: usr.sbin/vmd/atomicio.c
===================================================================
RCS file: usr.sbin/vmd/atomicio.c
diff -N usr.sbin/vmd/atomicio.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ usr.sbin/vmd/atomicio.c     6 May 2017 17:56:55 -0000
@@ -0,0 +1,153 @@
+/* $OpenBSD: atomicio.c,v 1.28 2016/07/27 23:18:12 djm Exp $ */
+/*
+ * Copyright (c) 2006 Damien Miller. All rights reserved.
+ * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
+ * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "atomicio.h"
+
+/*
+ * ensure all of data on socket comes through. f==read || f==vwrite
+ */
+size_t
+atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
+    int (*cb)(void *, size_t), void *cb_arg)
+{
+       char *s = _s;
+       size_t pos = 0;
+       ssize_t res;
+       struct pollfd pfd;
+
+       pfd.fd = fd;
+       pfd.events = f == read ? POLLIN : POLLOUT;
+       while (n > pos) {
+               res = (f) (fd, s + pos, n - pos);
+               switch (res) {
+               case -1:
+                       if (errno == EINTR)
+                               continue;
+                       if (errno == EAGAIN) {
+                               (void)poll(&pfd, 1, -1);
+                               continue;
+                       }
+                       return 0;
+               case 0:
+                       errno = EPIPE;
+                       return pos;
+               default:
+                       pos += (size_t)res;
+                       if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
+                               errno = EINTR;
+                               return pos;
+                       }
+               }
+       }
+       return pos;
+}
+
+size_t
+atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
+{
+       return atomicio6(f, fd, _s, n, NULL, NULL);
+}
+
+/*
+ * ensure all of data on socket comes through. f==readv || f==writev
+ */
+size_t
+atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
+    const struct iovec *_iov, int iovcnt,
+    int (*cb)(void *, size_t), void *cb_arg)
+{
+       size_t pos = 0, rem;
+       ssize_t res;
+       struct iovec iov_array[IOV_MAX], *iov = iov_array;
+       struct pollfd pfd;
+
+       if (iovcnt < 0 || iovcnt > IOV_MAX) {
+               errno = EINVAL;
+               return 0;
+       }
+       /* Make a copy of the iov array because we may modify it below */
+       memcpy(iov, _iov, (size_t)iovcnt * sizeof(*_iov));
+
+       pfd.fd = fd;
+       pfd.events = f == readv ? POLLIN : POLLOUT;
+       for (; iovcnt > 0 && iov[0].iov_len > 0;) {
+               res = (f) (fd, iov, iovcnt);
+               switch (res) {
+               case -1:
+                       if (errno == EINTR)
+                               continue;
+                       if (errno == EAGAIN) {
+                               (void)poll(&pfd, 1, -1);
+                               continue;
+                       }
+                       return 0;
+               case 0:
+                       errno = EPIPE;
+                       return pos;
+               default:
+                       rem = (size_t)res;
+                       pos += rem;
+                       /* skip completed iov entries */
+                       while (iovcnt > 0 && rem >= iov[0].iov_len) {
+                               rem -= iov[0].iov_len;
+                               iov++;
+                               iovcnt--;
+                       }
+                       /* This shouldn't happen... */
+                       if (rem > 0 && (iovcnt <= 0 || rem > iov[0].iov_len)) {
+                               errno = EFAULT;
+                               return 0;
+                       }
+                       if (iovcnt == 0)
+                               break;
+                       /* update pointer in partially complete iov */
+                       iov[0].iov_base = ((char *)iov[0].iov_base) + rem;
+                       iov[0].iov_len -= rem;
+               }
+               if (cb != NULL && cb(cb_arg, (size_t)res) == -1) {
+                       errno = EINTR;
+                       return pos;
+               }
+       }
+       return pos;
+}
+
+size_t
+atomiciov(ssize_t (*f) (int, const struct iovec *, int), int fd,
+    const struct iovec *_iov, int iovcnt)
+{
+       return atomiciov6(f, fd, _iov, iovcnt, NULL, NULL);
+}
Index: usr.sbin/vmd/atomicio.h
===================================================================
RCS file: usr.sbin/vmd/atomicio.h
diff -N usr.sbin/vmd/atomicio.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ usr.sbin/vmd/atomicio.h     6 May 2017 17:56:55 -0000
@@ -0,0 +1,51 @@
+/* $OpenBSD: atomicio.h,v 1.11 2010/09/22 22:58:51 djm Exp $ */
+
+/*
+ * Copyright (c) 2006 Damien Miller.  All rights reserved.
+ * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ATOMICIO_H
+#define _ATOMICIO_H
+
+/*
+ * Ensure all of data on socket comes through. f==read || f==vwrite
+ */
+size_t
+atomicio6(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n,
+    int (*cb)(void *, size_t), void *);
+size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
+
+#define vwrite (ssize_t (*)(int, void *, size_t))write
+
+/*
+ * ensure all of data on socket comes through. f==readv || f==writev
+ */
+size_t
+atomiciov6(ssize_t (*f) (int, const struct iovec *, int), int fd,
+    const struct iovec *_iov, int iovcnt, int (*cb)(void *, size_t), void *);
+size_t atomiciov(ssize_t (*)(int, const struct iovec *, int),
+    int, const struct iovec *, int);
+
+#endif /* _ATOMICIO_H */
Index: usr.sbin/vmd/i8253.c
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/i8253.c,v
retrieving revision 1.14
diff -u -p -a -u -r1.14 i8253.c
--- usr.sbin/vmd/i8253.c        28 Apr 2017 08:14:48 -0000      1.14
+++ usr.sbin/vmd/i8253.c        6 May 2017 17:56:55 -0000
@@ -25,10 +25,12 @@
#include <event.h>
#include <string.h>
#include <stddef.h>
+#include <unistd.h>

#include "i8253.h"
#include "proc.h"
#include "vmm.h"
+#include "atomicio.h"

extern char *__progname;

@@ -340,4 +342,47 @@ i8253_fire(int fd, short type, void *arg

        if (ctr->mode != TIMER_INTTC)
                evtimer_add(&ctr->timer, &tv);
+}
+
+int
+i8253_dump(int fd)
+{
+       log_debug("%s: sending PIT", __func__);
+       if (atomicio(vwrite, fd, &i8253_channel, sizeof(i8253_channel)) !=
+           sizeof(i8253_channel)) {
+               log_warnx("%s: error writing PIT to fd", __func__);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+i8253_restore(int fd, uint32_t vm_id)
+{
+       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);
+       return (0);
+}
+
+void
+i8253_stop()
+{
+       evtimer_del(&i8253_channel[0].timer);
+       evtimer_del(&i8253_channel[1].timer);
+       evtimer_del(&i8253_channel[2].timer);
}
Index: usr.sbin/vmd/i8253.h
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/i8253.h,v
retrieving revision 1.5
diff -u -p -a -u -r1.5 i8253.h
--- usr.sbin/vmd/i8253.h        28 Apr 2017 08:14:48 -0000      1.5
+++ usr.sbin/vmd/i8253.h        6 May 2017 17:56:55 -0000
@@ -44,5 +44,8 @@ struct i8253_channel {
void i8253_init(uint32_t);
void i8253_reset(uint8_t);
void i8253_fire(int, short, void *);
+int i8253_dump(int);
+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);
Index: usr.sbin/vmd/i8259.c
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/i8259.c,v
retrieving revision 1.13
diff -u -p -a -u -r1.13 i8259.c
--- usr.sbin/vmd/i8259.c        8 Apr 2017 19:06:29 -0000       1.13
+++ usr.sbin/vmd/i8259.c        6 May 2017 17:56:55 -0000
@@ -23,9 +23,11 @@

#include <machine/vmmvar.h>

+#include <unistd.h>
#include "proc.h"
#include "i8259.h"
#include "vmm.h"
+#include "atomicio.h"

struct i8259 {
        uint8_t irr;
@@ -646,4 +648,26 @@ vcpu_exit_i8259(struct vm_run_params *vr
        }

        return (0xFF);
+}
+
+int
+i8259_dump(int fd)
+{
+       log_debug("%s: sending PIC", __func__);
+       if (atomicio(vwrite, fd, &pics, sizeof(pics)) != sizeof(pics)) {
+               log_warnx("%s: error writing PIC to fd", __func__);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+i8259_restore(int fd)
+{
+       log_debug("%s: restoring PIC", __func__);
+       if (atomicio(read, fd, &pics, sizeof(pics)) != sizeof(pics)) {
+               log_warnx("%s: error reading PIC from fd", __func__);
+               return (-1);
+       }
+       return (0);
}
Index: usr.sbin/vmd/i8259.h
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/i8259.h,v
retrieving revision 1.2
diff -u -p -a -u -r1.2 i8259.h
--- usr.sbin/vmd/i8259.h        3 Oct 2016 06:00:17 -0000       1.2
+++ usr.sbin/vmd/i8259.h        6 May 2017 17:56:55 -0000
@@ -66,3 +66,5 @@ uint8_t vcpu_exit_i8259(struct vm_run_pa
void i8259_init(void);
uint16_t i8259_ack(void);
uint8_t i8259_is_pending(void);
+int i8259_restore(int);
+int i8259_dump(int);
Index: usr.sbin/vmd/mc146818.c
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/mc146818.c,v
retrieving revision 1.13
diff -u -p -a -u -r1.13 mc146818.c
--- usr.sbin/vmd/mc146818.c     2 May 2017 09:51:19 -0000       1.13
+++ usr.sbin/vmd/mc146818.c     6 May 2017 17:56:55 -0000
@@ -26,12 +26,14 @@
#include <stddef.h>
#include <string.h>
#include <time.h>
+#include <unistd.h>

#include "vmd.h"
#include "mc146818.h"
#include "proc.h"
#include "virtio.h"
#include "vmm.h"
+#include "atomicio.h"

#define MC_DIVIDER_MASK 0xe0
#define MC_RATE_MASK 0xf
@@ -312,4 +314,42 @@ vcpu_exit_mc146818(struct vm_run_params }

        return 0xFF;
+}
+
+int
+mc146818_dump(int fd)
+{
+       log_debug("%s: sending RTC", __func__);
+       if (atomicio(vwrite, fd, &rtc, sizeof(rtc)) != sizeof(rtc)) {
+               log_warnx("%s: error writing RTC to fd", __func__);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+mc146818_restore(int fd, uint32_t vm_id)
+{
+       log_debug("%s: restoring RTC", __func__);
+       if (atomicio(read, fd, &rtc, sizeof(rtc)) != sizeof(rtc)) {
+               log_warnx("%s: error reading RTC from fd", __func__);
+               return (-1);
+       }
+       rtc.vm_id = vm_id;
+
+       memset(&rtc.sec, 0, sizeof(struct event));
+       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);
+}
+
+void
+mc146818_stop()
+{
+       evtimer_del(&rtc.per);
+       evtimer_del(&rtc.sec);
}
Index: usr.sbin/vmd/mc146818.h
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/mc146818.h,v
retrieving revision 1.3
diff -u -p -a -u -r1.3 mc146818.h
--- usr.sbin/vmd/mc146818.h     23 Mar 2017 07:59:41 -0000      1.3
+++ usr.sbin/vmd/mc146818.h     6 May 2017 17:56:55 -0000
@@ -18,3 +18,6 @@
void mc146818_init(uint32_t, uint64_t, uint64_t);
uint8_t vcpu_exit_mc146818(struct vm_run_params *vrp);
void dump_mc146818(void);
+int mc146818_dump(int);
+int mc146818_restore(int, uint32_t);
+void mc146818_stop(void);
Index: usr.sbin/vmd/ns8250.c
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/ns8250.c,v
retrieving revision 1.7
diff -u -p -a -u -r1.7 ns8250.c
--- usr.sbin/vmd/ns8250.c       21 Mar 2017 03:29:57 -0000      1.7
+++ usr.sbin/vmd/ns8250.c       6 May 2017 17:56:55 -0000
@@ -31,6 +31,7 @@
#include "proc.h"
#include "vmd.h"
#include "vmm.h"
+#include "atomicio.h"

extern char *__progname;
struct ns8250_dev com1_dev;
@@ -483,4 +484,42 @@ vcpu_exit_com(struct vm_run_params *vrp)

        mutex_unlock(&com1_dev.mutex);
        return (intr);
+}
+
+int
+ns8250_dump(int fd)
+{
+       log_debug("%s: sending UART", __func__);
+       if (atomicio(vwrite, fd, &com1_dev.regs,
+           sizeof(com1_dev.regs)) != sizeof(com1_dev.regs)) {
+               log_warnx("%s: error writing UART to fd", __func__);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+ns8250_restore(int fd, int con_fd, uint32_t vmid)
+{
+       int ret;
+       log_debug("%s: receiving UART", __func__);
+       if (atomicio(read, fd, &com1_dev.regs,
+           sizeof(com1_dev.regs)) != sizeof(com1_dev.regs)) {
+               log_warnx("%s: error reading UART from fd", __func__);
+               return (-1);
+       }
+
+       ret = pthread_mutex_init(&com1_dev.mutex, NULL);
+       if (ret) {
+               errno = ret;
+               fatal("could not initialize com1 mutex");
+       }
+       com1_dev.fd = con_fd;
+       com1_dev.irq = 4;
+       com1_dev.rcv_pending = 0;
+
+       event_set(&com1_dev.event, com1_dev.fd, EV_READ | EV_PERSIST,
+           com_rcv_event, (void *)(intptr_t)vmid);
+       event_add(&com1_dev.event, NULL);
+       return (0);
}
Index: usr.sbin/vmd/ns8250.h
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/ns8250.h,v
retrieving revision 1.3
diff -u -p -a -u -r1.3 ns8250.h
--- usr.sbin/vmd/ns8250.h       3 Oct 2016 06:00:17 -0000       1.3
+++ usr.sbin/vmd/ns8250.h       6 May 2017 17:56:55 -0000
@@ -62,3 +62,5 @@ void vcpu_process_com_mcr(union vm_exit void vcpu_process_com_iir(union vm_exit *);
void vcpu_process_com_msr(union vm_exit *);
void vcpu_process_com_scr(union vm_exit *);
+int ns8250_dump(int);
+int ns8250_restore(int, int, uint32_t);
Index: usr.sbin/vmd/virtio.c
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/virtio.c,v
retrieving revision 1.44
diff -u -p -a -u -r1.44 virtio.c
--- usr.sbin/vmd/virtio.c       2 May 2017 09:51:19 -0000       1.44
+++ usr.sbin/vmd/virtio.c       6 May 2017 17:56:55 -0000
@@ -42,6 +42,7 @@
#include "vmm.h"
#include "virtio.h"
#include "loadfile.h"
+#include "atomicio.h"

extern char *__progname;

@@ -51,6 +52,7 @@ struct vionet_dev *vionet;
struct vmmci_dev vmmci;

int nr_vionet;
+int nr_vioblk;

#define MAXPHYS (64 * 1024)     /* max raw I/O transfer size */

@@ -1648,6 +1650,7 @@ virtio_init(struct vmd_vm *vm, int *chil
            + sizeof(uint16_t) * (2 + VIORND_QUEUE_SIZE));

        if (vcp->vcp_ndisks > 0) {
+               nr_vioblk = vcp->vcp_ndisks;
                vioblk = calloc(vcp->vcp_ndisks, sizeof(struct vioblk_dev));
                if (vioblk == NULL) {
                        log_warn("%s: calloc failure allocating vioblks",
@@ -1798,4 +1801,270 @@ virtio_init(struct vmd_vm *vm, int *chil
        vmmci.irq = pci_get_dev_irq(id);

        evtimer_set(&vmmci.timeout, vmmci_timeout, NULL);
+}
+
+int
+vmmci_restore(int fd, uint32_t vm_id)
+{
+       uint8_t id;
+
+       log_debug("%s: receiving vmmci", __func__);
+       if (atomicio(read, fd, &vmmci, sizeof(vmmci)) != sizeof(vmmci)) {
+               log_warnx("%s: error reading vmmci from fd", __func__);
+               return (-1);
+       }
+
+       if (pci_add_device(&id, PCI_VENDOR_OPENBSD,
+           PCI_PRODUCT_OPENBSD_CONTROL,
+           PCI_CLASS_COMMUNICATIONS,
+           PCI_SUBCLASS_COMMUNICATIONS_MISC,
+           PCI_VENDOR_OPENBSD,
+           PCI_PRODUCT_VIRTIO_VMMCI, 1, NULL)) {
+               log_warnx("%s: can't add PCI vmm control device",
+                   __progname);
+               return (-1);
+       }
+
+       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, vmmci_io, NULL)) {
+               log_warnx("%s: can't add bar for vmm control device",
+                   __progname);
+               return (-1);
+       }
+       vmmci.vm_id = vm_id;
+       memset(&vmmci.timeout, 0, sizeof(struct event));
+       evtimer_set(&vmmci.timeout, vmmci_timeout, NULL);
+       return (0);
+}
+
+int
+viornd_restore(int fd)
+{
+       uint8_t id;
+
+       log_debug("%s: receiving viornd", __func__);
+       if (atomicio(read, fd, &viornd, sizeof(viornd)) != sizeof(viornd)) {
+               log_warnx("%s: error reading viornd from fd", __func__);
+               return (-1);
+       }
+       if (pci_add_device(&id, PCI_VENDOR_QUMRANET,
+           PCI_PRODUCT_QUMRANET_VIO_RNG, PCI_CLASS_SYSTEM,
+           PCI_SUBCLASS_SYSTEM_MISC,
+           PCI_VENDOR_OPENBSD,
+           PCI_PRODUCT_VIRTIO_ENTROPY, 1, NULL)) {
+               log_warnx("%s: can't add PCI virtio rng device",
+                   __progname);
+               return (-1);
+       }
+
+       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_rnd_io, NULL)) {
+               log_warnx("%s: can't add bar for virtio rng device",
+                   __progname);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+vionet_restore(int fd, struct vmd_vm *vm, int *child_taps)
+{
+       struct vmop_create_params *vmc = &vm->vm_params;
+       struct vm_create_params *vcp = &vmc->vmc_params;
+       uint8_t i, id;
+       int ret;
+
+       nr_vionet = vcp->vcp_nnics;
+       if (vcp->vcp_nnics > 0) {
+               vionet = calloc(vcp->vcp_nnics, sizeof(struct vionet_dev));
+               if (vionet == NULL) {
+                       log_warn("%s: calloc failure allocating vionets",
+                           __progname);
+                       return (-1);
+               }
+               log_debug("%s: receiving vionet", __func__);
+               if (atomicio(read, fd, vionet,
+                   vcp->vcp_nnics * sizeof(struct vionet_dev)) !=
+                   vcp->vcp_nnics * sizeof(struct vionet_dev)) {
+                       log_warnx("%s: error reading vionet from fd",
+                           __func__);
+                       return (-1);
+               }
+
+               /* Virtio network */
+               for (i = 0; i < vcp->vcp_nnics; i++) {
+                       if (pci_add_device(&id, PCI_VENDOR_QUMRANET,
+                           PCI_PRODUCT_QUMRANET_VIO_NET, PCI_CLASS_SYSTEM,
+                           PCI_SUBCLASS_SYSTEM_MISC,
+                           PCI_VENDOR_OPENBSD,
+                           PCI_PRODUCT_VIRTIO_NETWORK, 1, NULL)) {
+                               log_warnx("%s: can't add PCI virtio net device",
+                                   __progname);
+                               return (-1);
+                       }
+
+                       if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_net_io,
+                           &vionet[i])) {
+                               log_warnx("%s: can't add bar for virtio net "
+                                   "device", __progname);
+                               return (-1);
+                       }
+
+                       memset(&vionet[i].mutex, 0, sizeof(pthread_mutex_t));
+                       ret = pthread_mutex_init(&vionet[i].mutex, NULL);
+
+                       if (ret) {
+                               errno = ret;
+                               log_warn("%s: could not initialize mutex "
+                                   "for vionet device", __progname);
+                               return (-1);
+                       }
+                       vionet[i].fd = child_taps[i];
+                       vionet[i].rx_pending = 0;
+                       vionet[i].vm_id = vcp->vcp_id;
+                       vionet[i].vm_vmid = vm->vm_vmid;
+
+                       memset(&vionet[i].event, 0, sizeof(struct event));
+                       event_set(&vionet[i].event, vionet[i].fd,
+                           EV_READ | EV_PERSIST, vionet_rx_event, &vionet[i]);
+                       if (event_add(&vionet[i].event, NULL)) {
+                               log_warn("could not initialize vionet event "
+                                   "handler");
+                               return (-1);
+                       }
+               }
+       }
+       return (0);
+}
+
+int
+vioblk_restore(int fd, struct vm_create_params *vcp, int *child_disks)
+{
+       uint8_t i, id;
+       off_t sz;
+
+       nr_vioblk = vcp->vcp_ndisks;
+       vioblk = calloc(vcp->vcp_ndisks, sizeof(struct vioblk_dev));
+       if (vioblk == NULL) {
+               log_warn("%s: calloc failure allocating vioblks", __progname);
+               return (-1);
+       }
+       log_debug("%s: receiving vioblk", __func__);
+       if (atomicio(read, fd, vioblk,
+           nr_vioblk * sizeof(struct vioblk_dev)) !=
+           nr_vioblk * sizeof(struct vioblk_dev)) {
+               log_warnx("%s: error reading vioblk from fd", __func__);
+               return (-1);
+       }
+       for (i = 0; i < vcp->vcp_ndisks; i++) {
+               if ((sz = lseek(child_disks[i], 0, SEEK_END)) == -1)
+                       continue;
+
+               if (pci_add_device(&id, PCI_VENDOR_QUMRANET,
+                   PCI_PRODUCT_QUMRANET_VIO_BLOCK,
+                   PCI_CLASS_MASS_STORAGE,
+                   PCI_SUBCLASS_MASS_STORAGE_SCSI,
+                   PCI_VENDOR_OPENBSD,
+                   PCI_PRODUCT_VIRTIO_BLOCK, 1, NULL)) {
+                       log_warnx("%s: can't add PCI virtio block "
+                           "device", __progname);
+                       return (-1);
+               }
+               if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_blk_io,
+                   &vioblk[i])) {
+                       log_warnx("%s: can't add bar for virtio block "
+                           "device", __progname);
+                       return (-1);
+               }
+               vioblk[i].fd = child_disks[i];
+       }
+       return (0);
+}
+
+int
+virtio_restore(int fd, struct vmd_vm *vm, int *child_disks, int *child_taps)
+{
+       struct vmop_create_params *vmc = &vm->vm_params;
+       struct vm_create_params *vcp = &vmc->vmc_params;
+       int ret;
+
+       if ((ret = viornd_restore(fd)) == -1)
+               return ret;
+
+       if ((ret = vioblk_restore(fd, vcp, child_disks)) == -1)
+               return ret;
+
+       if ((ret = vionet_restore(fd, vm, child_taps)) == -1)
+               return ret;
+
+       if ((ret = vmmci_restore(fd, vcp->vcp_id)) == -1)
+               return ret;
+
+       return (0);
+}
+
+int
+viornd_dump(int fd)
+{
+       log_debug("%s: sending viornd", __func__);
+       if (atomicio(vwrite, fd, &viornd, sizeof(viornd)) != sizeof(viornd)) {
+               log_warnx("%s: error writing viornd to fd", __func__);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+vmmci_dump(int fd)
+{
+       log_debug("%s: sending vmmci", __func__);
+       if (atomicio(vwrite, fd, &vmmci, sizeof(vmmci)) != sizeof(vmmci)) {
+               log_warnx("%s: error writing vmmci to fd", __func__);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+vionet_dump(int fd)
+{
+       log_debug("%s: sending vionet", __func__);
+       if (atomicio(vwrite, fd, vionet,
+           nr_vionet * sizeof(struct vionet_dev)) !=
+           nr_vionet * sizeof(struct vionet_dev)) {
+               log_warnx("%s: error writing vionet to fd", __func__);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+vioblk_dump(int fd)
+{
+       log_debug("%s: sending vioblk", __func__);
+       if (atomicio(vwrite, fd, vioblk,
+           nr_vioblk * sizeof(struct vioblk_dev)) !=
+           nr_vioblk * sizeof(struct vioblk_dev)) {
+               log_warnx("%s: error writing vioblk to fd", __func__);
+               return (-1);
+       }
+       return (0);
+}
+
+int
+virtio_dump(int fd)
+{
+       int ret;
+
+       if ((ret = viornd_dump(fd)) == -1)
+               return ret;
+
+       if ((ret = vioblk_dump(fd)) == -1)
+               return ret;
+
+       if ((ret = vionet_dump(fd)) == -1)
+               return ret;
+
+       if ((ret = vmmci_dump(fd)) == -1);
+               return ret;
+
+       return (0);
}
Index: usr.sbin/vmd/virtio.h
===================================================================
RCS file: /home/pdvyas/cvs/src/usr.sbin/vmd/virtio.h,v
retrieving revision 1.16
diff -u -p -a -u -r1.16 virtio.h
--- usr.sbin/vmd/virtio.h       2 May 2017 09:51:19 -0000       1.16
+++ usr.sbin/vmd/virtio.h       6 May 2017 17:56:55 -0000
@@ -161,19 +161,27 @@ struct vmmci_dev {

/* virtio.c */
void virtio_init(struct vmd_vm *, int *, int *);
+int virtio_dump(int);
+int virtio_restore(int, struct vmd_vm *, int *, int *);
uint32_t vring_size(uint32_t);

int virtio_rnd_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t);
+int viornd_dump(int);
+int viornd_restore(int);
void viornd_update_qs(void);
void viornd_update_qa(void);
int viornd_notifyq(void);

int virtio_blk_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t);
+int vioblk_dump(int);
+int vioblk_restore(int, struct vm_create_params *, int *);
void vioblk_update_qs(struct vioblk_dev *);
void vioblk_update_qa(struct vioblk_dev *);
int vioblk_notifyq(struct vioblk_dev *);

int virtio_net_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t);
+int vionet_dump(int);
+int vionet_restore(int, struct vmd_vm *, int *);
void vionet_update_qs(struct vionet_dev *);
void vionet_update_qa(struct vionet_dev *);
int vionet_notifyq(struct vionet_dev *);
@@ -182,6 +190,8 @@ void vionet_process_rx(uint32_t);
int vionet_enq_rx(struct vionet_dev *, char *, ssize_t, int *);

int vmmci_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t);
+int vmmci_dump(int);
+int vmmci_restore(int, uint32_t);
int vmmci_ctl(unsigned int);
void vmmci_ack(unsigned int);
void vmmci_timeout(int, short, void *);

Reply via email to