diff --git a/vchan/Makefile.stubdom b/vchan/Makefile.stubdom new file mode 100644 index 00000000..af716cef --- /dev/null +++ b/vchan/Makefile.stubdom @@ -0,0 +1,36 @@ +# +# The Qubes OS Project, http://www.qubes-os.org +# +# Copyright (C) 2012 Marek Marczykowski +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# + +# Assume it is placed as xen-root/tools/vchan + +XEN_ROOT = ../.. +include $(XEN_ROOT)/tools/Rules.mk + +CFLAGS+=-Wall -I$(XEN_ROOT)/tools/libxc -DCONFIG_STUBDOM +all: libvchan.a + +libvchan.a: init.o io.o + $(AR) rc $@ $^ + +clean: + rm -f *.o *so *~ client server node node-select + + diff --git a/vchan/init.c b/vchan/init.c index 30cc2001..d0127939 100644 --- a/vchan/init.c +++ b/vchan/init.c @@ -19,6 +19,9 @@ * */ +#include +#include +#include #include #include #include @@ -29,25 +32,38 @@ #include #include #include +#include #include "libvchan.h" +#ifndef CONFIG_STUBDOM #include "../u2mfn/u2mfnlib.h" +#endif static int ring_init(struct libvchan *ctrl) { - int u2mfn = open("/proc/u2mfn", O_RDONLY); int mfn; struct vchan_interface *ring; +#ifdef CONFIG_STUBDOM + ring = (struct vchan_interface *) memalign(XC_PAGE_SIZE, sizeof(*ring)); + + if (!ring) + return -1; + + + mfn = virtual_to_mfn(ring); +#else + int u2mfn = open("/proc/u2mfn", O_RDONLY); ring = (struct vchan_interface *) u2mfn_alloc_kpage (); - + if (ring == MAP_FAILED) return -1; - ctrl->ring = ring; if (u2mfn_get_last_mfn (&mfn) < 0) return -1; - - ctrl->ring_ref = mfn; close(u2mfn); +#endif + + ctrl->ring = ring; + ctrl->ring_ref = mfn; ring->cons_in = ring->prod_in = ring->cons_out = ring->prod_out = 0; ring->server_closed = ring->client_closed = 0; @@ -65,13 +81,18 @@ static int server_interface_init(struct libvchan *ctrl, int devno) struct xs_handle *xs; char buf[64]; char ref[16]; + /* XXX temp hack begin */ + char *domid_s; + int domid = 0; + unsigned int len; + /* XXX temp hack end */ #ifdef XENCTRL_HAS_XC_INTERFACE xc_evtchn *evfd; #else int evfd; #endif evtchn_port_or_error_t port; - xs = xs_domain_open(); + xs = xs_daemon_open(); if (!xs) { return ret; } @@ -90,20 +111,41 @@ static int server_interface_init(struct libvchan *ctrl, int devno) if (port < 0) goto fail2; ctrl->evport = port; + ctrl->devno = devno; + + // stubdom debug HACK XXX + domid_s = xs_read(xs, 0, "domid", &len); + if (domid_s) + domid = atoi(domid_s); + snprintf(ref, sizeof ref, "%d", ctrl->ring_ref); snprintf(buf, sizeof buf, "device/vchan/%d/ring-ref", devno); if (!xs_write(xs, 0, buf, ref, strlen(ref))) +#ifdef CONFIG_STUBDOM + // TEMP HACK XXX FIXME goto fail2; + fprintf(stderr, "xenstore-write /local/domain/%d/%s %s\n", domid, buf, ref); +#else goto fail2; +#endif snprintf(ref, sizeof ref, "%d", ctrl->evport); snprintf(buf, sizeof buf, "device/vchan/%d/event-channel", devno); if (!xs_write(xs, 0, buf, ref, strlen(ref))) +#ifdef CONFIG_STUBDOM + // TEMP HACK XXX FIXME goto fail2; + fprintf(stderr, "xenstore-write /local/domain/%d/%s %s\n", domid, buf, ref); +#else goto fail2; +#endif + // do not block in stubdom - libvchan_server_handle_connected will be + // called on first input +#ifndef CONFIG_STUBDOM // wait for the peer to arrive if (xc_evtchn_pending(evfd) == -1) goto fail2; xc_evtchn_unmask(ctrl->evfd, ctrl->evport); snprintf(buf, sizeof buf, "device/vchan/%d", devno); xs_rm(xs, 0, buf); +#endif ret = 0; fail2: @@ -129,8 +171,8 @@ static int server_interface_init(struct libvchan *ctrl, int devno) ctrl->rd_ring_size = sizeof(ctrl->ring->buf_##dir2) /** - Run in AppVM (any domain). - Sleeps until the connection is established. + Run in AppVM (any domain). + Sleeps until the connection is established. (unless in stubdom) \param devno something like a well-known port. \returns NULL on failure, handle on success */ @@ -156,6 +198,39 @@ struct libvchan *libvchan_server_init(int devno) return ctrl; } +int libvchan_server_handle_connected(struct libvchan *ctrl) +{ + struct xs_handle *xs; + char buf[64]; + int ret = -1; + int libvchan_fd; + fd_set rfds; + + xs = xs_daemon_open(); + if (!xs) { + return ret; + } + // clear the pending flag + xc_evtchn_pending(ctrl->evfd); + + snprintf(buf, sizeof buf, "device/vchan/%d", ctrl->devno); + xs_rm(xs, 0, buf); + + ret = 0; + +#if 0 +fail2: + if (ret) +#ifdef XENCTRL_HAS_XC_INTERFACE + xc_evtchn_close(ctrl->evfd); +#else + close(ctrl->evfd); +#endif +#endif + xs_daemon_close(xs); + return ret; +} + /** retrieves ring-ref and event-channel numbers from xenstore (if they don't exist, return error, because nobody seems to listen); @@ -250,7 +325,7 @@ static int client_interface_init(struct libvchan *ctrl, int domain, int devno) /** Run on the client side of connection (currently, must be dom0). \returns NULL on failure (e.g. noone listening), handle on success -*/ +*/ struct libvchan *libvchan_client_init(int domain, int devno) { struct libvchan *ctrl = diff --git a/vchan/io.c b/vchan/io.c index 6b16f406..23135a25 100644 --- a/vchan/io.c +++ b/vchan/io.c @@ -22,6 +22,8 @@ #include "libvchan.h" #include #include +#include +#include /** \return How much data is immediately available for reading */ @@ -67,7 +69,24 @@ int libvchan_is_eof(struct libvchan *ctrl) int libvchan_wait(struct libvchan *ctrl) { int ret; +#ifndef CONFIG_STUBDOM ret = xc_evtchn_pending(ctrl->evfd); +#else + int vchan_fd = libvchan_fd_for_select(ctrl); + fd_set rfds; + + libvchan_prepare_to_select(ctrl); + while ((ret = xc_evtchn_pending(ctrl->evfd)) < 0) { + FD_ZERO(&rfds); + FD_SET(0, &rfds); + FD_SET(vchan_fd, &rfds); + ret = select(vchan_fd + 1, &rfds, NULL, NULL, NULL); + if (ret < 0 && errno != EINTR) { + perror("select"); + return ret; + } + } +#endif if (ret!=-1 && xc_evtchn_unmask(ctrl->evfd, ctrl->evport)) return -1; if (ret!=-1 && libvchan_is_eof(ctrl)) diff --git a/vchan/libvchan.h b/vchan/libvchan.h index 6a6025fb..3f647462 100644 --- a/vchan/libvchan.h +++ b/vchan/libvchan.h @@ -19,6 +19,9 @@ * */ +#ifndef _LIBVCHAN_H +#define _LIBVCHAN_H + #include #include typedef uint32_t VCHAN_RING_IDX; @@ -44,6 +47,7 @@ struct libvchan { int evfd; #endif int evport; + int devno; VCHAN_RING_IDX *wr_cons, *wr_prod, *rd_cons, *rd_prod; char *rd_ring, *wr_ring; int rd_ring_size, wr_ring_size; @@ -51,6 +55,7 @@ struct libvchan { }; struct libvchan *libvchan_server_init(int devno); +int libvchan_server_handle_connected(struct libvchan *ctrl); struct libvchan *libvchan_client_init(int domain, int devno); @@ -63,3 +68,5 @@ int libvchan_fd_for_select(struct libvchan *ctrl); int libvchan_is_eof(struct libvchan *ctrl); int libvchan_data_ready(struct libvchan *ctrl); int libvchan_buffer_space(struct libvchan *ctrl); + +#endif /* _LIBVCHAN_H */