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 *);