On Thu, May 04, 2017 at 08:57:00PM -0700, Pratik Vyas wrote:
> Hello tech@,
> 
> This patch adds functions to read and write state of devices in vmd. The
> atomicio parts are copied from usr.bin/ssh.
> 
> Context: This is required for implementing vmctl send and vmctl receive.
> vmctl send / receive are two new options that will support snapshotting
> VMs and migrating VMs from one host to another. This project was
> undertaken at San Jose State University along with my three teammates,
> Ashwin, Harshada and Siri with mlarkin@ as our advisor.
> 
> We are working with reyk@ on cleaning up rest of the vmd changes.
> 
> Thanks,
> Pratik
> 
> 

I have already reviewed the device bits (i8253/i8259/ns8250/mc146818).

Those are ok mlarkin@.

I'll let reyk@ comment on the rest, I know he has been working with
Pratik over the past few days getting this ready.

-ml

> 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     5 May 2017 03:43:41 -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   5 May 2017 03:43:41 -0000
> @@ -0,0 +1,306 @@
> +/* $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);
> +}
> +/* $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   5 May 2017 03:43:41 -0000
> @@ -0,0 +1,102 @@
> +/* $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 */
> +/* $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      5 May 2017 03:43:41 -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      5 May 2017 03:43:41 -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      5 May 2017 03:43:41 -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      5 May 2017 03:43:41 -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   5 May 2017 03:43:41 -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   5 May 2017 03:43:41 -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     5 May 2017 03:43:41 -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     5 May 2017 03:43:41 -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     5 May 2017 03:43:41 -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,274 @@ 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 vm_create_params *vcp, int *child_taps)
> +{
> +     int ret;
> +     uint8_t i, id;
> +
> +     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;
> +
> +                     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 vm_create_params *vcp,
> +    int *child_disks, int *child_taps)
> +{
> +     int ret;
> +
> +     ret = viornd_restore(fd);
> +     if (ret)
> +             return ret;
> +
> +     ret = vioblk_restore(fd, vcp, child_disks);
> +     if (ret)
> +             return ret;
> +
> +     ret = vionet_restore(fd, vcp, child_taps);
> +     if (ret)
> +             return ret;
> +
> +     ret = vmmci_restore(fd, vcp->vcp_id);
> +     if (ret)
> +             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;
> +
> +     ret = viornd_dump(fd);
> +     if (ret)
> +             return ret;
> +
> +     ret = vioblk_dump(fd);
> +     if (ret)
> +             return ret;
> +
> +     ret = vionet_dump(fd);
> +     if (ret)
> +             return ret;
> +
> +     ret = vmmci_dump(fd);
> +     if (ret)
> +             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     5 May 2017 03:43:41 -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 vm_create_params *, 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 vm_create_params *, 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