From: Paul Durrant Date: Thu, 30 Jan 2014 13:09:35 +0000 (+0000) Subject: Update to new, slightly modified, ioreq server API and rename main.c X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=9a6991a8e9cdb2f16bca1045917312b80cc1ec48;p=people%2Fpauldu%2Fdemu.git Update to new, slightly modified, ioreq server API and rename main.c to demu.c. Signed-off-by: Paul Durrant --- diff --git a/Makefile b/Makefile index eaddd3b..f7bcbd4 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ TARGET = demu OBJS := device.o \ pci.o \ - main.o + demu.o CFLAGS = -I$(shell pwd)/include diff --git a/demu.c b/demu.c new file mode 100644 index 0000000..0c49d49 --- /dev/null +++ b/demu.c @@ -0,0 +1,815 @@ +/* + * Copyright (c) 2012, Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 COPYRIGHT + * HOLDER OR CONTRIBUTORS 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "debug.h" +#include "device.h" +#include "pci.h" + +#define FALSE 0 + +#define mb() asm volatile ("" : : : "memory") + +enum { + DEMU_OPT_DOMAIN, + DEMU_OPT_VCPUS, + DEMU_OPT_BUS, + DEMU_OPT_DEVICE, + DEMU_OPT_FUNCTION, + DEMU_NR_OPTS + }; + +static struct option demu_option[] = { + {"domain", 1, NULL, 0}, + {"vcpus", 1, NULL, 0}, + {"bus", 1, NULL, 0}, + {"device", 1, NULL, 0}, + {"function", 1, NULL, 0}, + {NULL, 0, NULL, 0} +}; + +static const char *demu_option_text[] = { + "", + "", + "", + "", + "", + NULL +}; + +static const char *prog; + +static void +usage(void) +{ + int i; + + fprintf(stderr, "Usage: %s \n\n", prog); + + for (i = 0; i < DEMU_NR_OPTS; i++) + fprintf(stderr, "\t--%s %s\n", + demu_option[i].name, + demu_option_text[i]); + + fprintf(stderr, "\n"); + + exit(2); +} + +typedef enum { + DEMU_SEQ_UNINITIALIZED = 0, + DEMU_SEQ_INTERFACE_OPEN, + DEMU_SEQ_SERVER_REGISTERED, + DEMU_SEQ_SHARED_IOPAGE_MAPPED, + DEMU_SEQ_BUFFERED_IOPAGE_MAPPED, + DEMU_SEQ_PORT_ARRAY_ALLOCATED, + DEMU_SEQ_EVTCHN_OPEN, + DEMU_SEQ_PORTS_BOUND, + DEMU_SEQ_BUF_PORT_BOUND, + DEMU_SEQ_INITIALIZED, + DEMU_NR_SEQS +} demu_seq_t; + +typedef struct demu_state { + demu_seq_t seq; + xc_interface *xch; + xc_interface *xceh; + domid_t domid; + unsigned int vcpus; + ioservid_t ioservid; + shared_iopage_t *iopage; + evtchn_port_t *ioreq_local_port; + buffered_iopage_t *buffered_iopage; + evtchn_port_t buf_ioreq_port; + evtchn_port_t buf_ioreq_local_port; +} demu_state_t; + +static demu_state_t demu_state; + +static void +handle_pio(ioreq_t *ioreq) +{ + if (ioreq->dir == IOREQ_READ) { + if (!ioreq->data_is_ptr) { + ioreq->data = (uint64_t)pci_bar_read(0, ioreq->addr, ioreq->size); + } else { + assert(FALSE); + } + } else if (ioreq->dir == IOREQ_WRITE) { + if (!ioreq->data_is_ptr) { + pci_bar_write(0, ioreq->addr, ioreq->size, (uint32_t)ioreq->data); + } else { + assert(FALSE); + } + } +} + +static void +handle_copy(ioreq_t *ioreq) +{ + if (ioreq->dir == IOREQ_READ) { + if (!ioreq->data_is_ptr) { + ioreq->data = (uint64_t)pci_bar_read(1, ioreq->addr, ioreq->size); + } else { + assert(FALSE); + } + } else if (ioreq->dir == IOREQ_WRITE) { + if (!ioreq->data_is_ptr) { + pci_bar_write(1, ioreq->addr, ioreq->size, (uint32_t)ioreq->data); + } else { + assert(FALSE); + } + } +} + +static void +handle_pci_config(ioreq_t *ioreq) +{ + if (ioreq->dir == IOREQ_READ) { + if (!ioreq->data_is_ptr) { + ioreq->data = (uint32_t)pci_config_read(ioreq->addr, ioreq->size); + } else { + assert(FALSE); + } + } else if (ioreq->dir == IOREQ_WRITE) { + if (!ioreq->data_is_ptr) { + pci_config_write(ioreq->addr, ioreq->size, (uint32_t)ioreq->data); + } else { + assert(FALSE); + } + } +} + +static void +handle_ioreq(ioreq_t *ioreq) +{ + switch (ioreq->type) { + case IOREQ_TYPE_PIO: + handle_pio(ioreq); + break; + + case IOREQ_TYPE_COPY: + handle_copy(ioreq); + break; + + case IOREQ_TYPE_PCI_CONFIG: + handle_pci_config(ioreq); + break; + + case IOREQ_TYPE_TIMEOFFSET: + break; + + case IOREQ_TYPE_INVALIDATE: + break; + + default: + DBG("UNKNOWN (%02x)", ioreq->type); + break; + } +} + +static void +demu_seq_next(void) +{ + assert(demu_state.seq < DEMU_SEQ_INITIALIZED); + + switch (++demu_state.seq) { + case DEMU_SEQ_INTERFACE_OPEN: + DBG(">INTERFACE_OPEN\n"); + break; + + case DEMU_SEQ_SERVER_REGISTERED: + DBG(">SERVER_REGISTERED\n"); + DBG("ioservid = %u\n", demu_state.ioservid); + break; + + case DEMU_SEQ_SHARED_IOPAGE_MAPPED: + DBG(">SHARED_IOPAGE_MAPPED\n"); + DBG("iopage = %p\n", demu_state.iopage); + break; + + case DEMU_SEQ_BUFFERED_IOPAGE_MAPPED: + DBG(">BUFFERED_IOPAGE_MAPPED\n"); + DBG("buffered_iopage = %p\n", demu_state.buffered_iopage); + break; + + case DEMU_SEQ_PORT_ARRAY_ALLOCATED: + DBG(">PORT_ARRAY_ALLOCATED\n"); + break; + + case DEMU_SEQ_EVTCHN_OPEN: + DBG(">EVTCHN_OPEN\n"); + break; + + case DEMU_SEQ_PORTS_BOUND: { + int i; + + DBG(">EVTCHN_PORTS_BOUND\n"); + + for (i = 0; i < demu_state.vcpus; i++) + DBG("VCPU%d: %u -> %u\n", i, + demu_state.iopage->vcpu_ioreq[i].vp_eport, + demu_state.ioreq_local_port[i]); + + break; + } + + case DEMU_SEQ_BUF_PORT_BOUND: + DBG(">EVTCHN_BUF_PORT_BOUND\n"); + + DBG("%u -> %u\n", + demu_state.buf_ioreq_port, + demu_state.buf_ioreq_local_port); + break; + + case DEMU_SEQ_INITIALIZED: + DBG(">INITIALIZED\n"); + break; + + default: + assert(FALSE); + break; + } +} + +static void +demu_teardown(void) +{ + if (demu_state.seq == DEMU_SEQ_INITIALIZED) { + DBG("= DEMU_SEQ_PORTS_BOUND) { + DBG("= DEMU_SEQ_PORTS_BOUND) { + DBG("= DEMU_SEQ_EVTCHN_OPEN) { + int i; + + DBG("= 0) { + DBG("VCPU%d: %u\n", i, port); + (void) xc_evtchn_unbind(demu_state.xceh, port); + } + } + + xc_evtchn_close(demu_state.xceh); + + demu_state.seq = DEMU_SEQ_PORT_ARRAY_ALLOCATED; + } + + if (demu_state.seq >= DEMU_SEQ_PORT_ARRAY_ALLOCATED) { + DBG("= DEMU_SEQ_BUFFERED_IOPAGE_MAPPED) { + DBG("= DEMU_SEQ_SHARED_IOPAGE_MAPPED) { + DBG("= DEMU_SEQ_SERVER_REGISTERED) { + DBG("= DEMU_SEQ_INTERFACE_OPEN) { + DBG("vcpu_ioreq[i].vp_eport; + + rc = xc_evtchn_bind_interdomain(demu_state.xceh, demu_state.domid, + port); + if (rc < 0) + goto fail9; + + demu_state.ioreq_local_port[i] = rc; + } + + demu_seq_next(); + + rc = xc_evtchn_bind_interdomain(demu_state.xceh, demu_state.domid, + buf_port); + if (rc < 0) + goto fail10; + + demu_state.buf_ioreq_local_port = rc; + + demu_seq_next(); + + rc = device_initialize(demu_state.xch, demu_state.domid, + demu_state.ioservid, bus, device, function); + if (rc < 0) + goto fail11; + + demu_seq_next(); + + assert(demu_state.seq == DEMU_SEQ_INITIALIZED); + return 0; + +fail11: + DBG("fail11\n"); + +fail10: + DBG("fail10\n"); + +fail9: + DBG("fail9\n"); + +fail8: + DBG("fail8\n"); + +fail7: + DBG("fail7\n"); + +fail6: + DBG("fail6\n"); + +fail5: + DBG("fail5\n"); + +fail4: + DBG("fail4\n"); + +fail3: + DBG("fail3\n"); + +fail2: + DBG("fail2\n"); + +fail1: + DBG("fail1\n"); + + warn("fail"); + return -1; +} + +static void +demu_poll_buffered_iopage(void) +{ + if (demu_state.seq != DEMU_SEQ_INITIALIZED) + return; + + for (;;) { + unsigned int read_pointer; + unsigned int write_pointer; + + read_pointer = demu_state.buffered_iopage->read_pointer; + write_pointer = demu_state.buffered_iopage->write_pointer; + + if (read_pointer == write_pointer) + break; + + while (read_pointer != write_pointer) { + unsigned int slot; + buf_ioreq_t *buf_ioreq; + ioreq_t ioreq; + + slot = read_pointer % IOREQ_BUFFER_SLOT_NUM; + + buf_ioreq = &demu_state.buffered_iopage->buf_ioreq[slot]; + + ioreq.size = 1UL << buf_ioreq->size; + ioreq.count = 1; + ioreq.addr = buf_ioreq->addr; + ioreq.data = buf_ioreq->data; + ioreq.state = STATE_IOREQ_READY; + ioreq.dir = buf_ioreq->dir; + ioreq.df = 1; + ioreq.type = buf_ioreq->type; + ioreq.data_is_ptr = 0; + + read_pointer++; + + if (ioreq.size == 8) { + slot = read_pointer % IOREQ_BUFFER_SLOT_NUM; + buf_ioreq = &demu_state.buffered_iopage->buf_ioreq[slot]; + + ioreq.data |= ((uint64_t)buf_ioreq->data) << 32; + + read_pointer++; + } + + handle_ioreq(&ioreq); + mb(); + } + + demu_state.buffered_iopage->read_pointer = read_pointer; + mb(); + } +} + +static void +demu_poll_iopage(unsigned int i) +{ + ioreq_t *ioreq; + + if (demu_state.seq != DEMU_SEQ_INITIALIZED) + return; + + ioreq = &demu_state.iopage->vcpu_ioreq[i]; + if (ioreq->state != STATE_IOREQ_READY) { + fprintf(stderr, "IO request not ready\n"); + return; + } + mb(); + + ioreq->state = STATE_IOREQ_INPROCESS; + + handle_ioreq(ioreq); + mb(); + + ioreq->state = STATE_IORESP_READY; + mb(); + + xc_evtchn_notify(demu_state.xceh, demu_state.ioreq_local_port[i]); +} + +static void +demu_poll_iopages(void) +{ + evtchn_port_t port; + int i; + + if (demu_state.seq != DEMU_SEQ_INITIALIZED) + return; + + port = xc_evtchn_pending(demu_state.xceh); + if (port < 0) + return; + + if (port == demu_state.buf_ioreq_local_port) { + xc_evtchn_unmask(demu_state.xceh, port); + demu_poll_buffered_iopage(); + } else { + for (i = 0; i < demu_state.vcpus; i++) { + if (port == demu_state.ioreq_local_port[i]) { + xc_evtchn_unmask(demu_state.xceh, port); + demu_poll_iopage(i); + } + } + } +} + +int +main(int argc, char **argv, char **envp) +{ + char *domain_str; + char *vcpus_str; + char *bus_str; + char *device_str; + char *function_str; + int index; + char *end; + domid_t domid; + unsigned int vcpus; + unsigned int bus; + unsigned int device; + unsigned int function; + sigset_t block; + struct pollfd pfd; + int rc; + + prog = basename(argv[0]); + + domain_str = NULL; + vcpus_str = NULL; + bus_str = NULL; + device_str = NULL; + function_str = NULL; + + for (;;) { + char c; + + c = getopt_long(argc, argv, "", demu_option, &index); + if (c == -1) + break; + + DBG("--%s = '%s'\n", demu_option[index].name, optarg); + + assert(c == 0); + switch (index) { + case DEMU_OPT_DOMAIN: + domain_str = optarg; + break; + + case DEMU_OPT_VCPUS: + vcpus_str = optarg; + break; + + case DEMU_OPT_BUS: + bus_str = optarg; + break; + + case DEMU_OPT_DEVICE: + device_str = optarg; + break; + + case DEMU_OPT_FUNCTION: + function_str = optarg; + break; + + default: + assert(FALSE); + break; + } + } + + if (domain_str == NULL || + vcpus_str == NULL || + bus_str == NULL || + device_str == NULL || + function_str == NULL) { + usage(); + /*NOTREACHED*/ + } + + domid = (domid_t)strtol(domain_str, &end, 0); + if (*end != '\0') { + fprintf(stderr, "invalid domain '%s'\n", domain_str); + exit(1); + } + + vcpus = (unsigned int)strtol(vcpus_str, &end, 0); + if (*end != '\0') { + fprintf(stderr, "invalid vcpu count '%s'\n", vcpus_str); + exit(1); + } + + bus = (unsigned int)strtol(bus_str, &end, 0); + if (*end != '\0') { + fprintf(stderr, "invalid bus '%s'\n", bus_str); + exit(1); + } + + device = (unsigned int)strtol(device_str, &end, 0); + if (*end != '\0') { + fprintf(stderr, "invalid vcpu count '%s'\n", device_str); + exit(1); + } + + function = (unsigned int)strtol(function_str, &end, 0); + if (*end != '\0') { + fprintf(stderr, "invalid vcpu count '%s'\n", function_str); + exit(1); + } + + sigfillset(&block); + + memset(&sigterm_handler, 0, sizeof (struct sigaction)); + sigterm_handler.sa_handler = demu_sigterm; + + sigaction(SIGTERM, &sigterm_handler, NULL); + sigdelset(&block, SIGTERM); + + sigaction(SIGINT, &sigterm_handler, NULL); + sigdelset(&block, SIGINT); + + sigaction(SIGHUP, &sigterm_handler, NULL); + sigdelset(&block, SIGHUP); + + sigaction(SIGABRT, &sigterm_handler, NULL); + sigdelset(&block, SIGABRT); + + memset(&sigusr1_handler, 0, sizeof (struct sigaction)); + sigusr1_handler.sa_handler = demu_sigusr1; + + sigaction(SIGUSR1, &sigusr1_handler, NULL); + sigdelset(&block, SIGUSR1); + + sigprocmask(SIG_BLOCK, &block, NULL); + + rc = demu_initialize(domid, vcpus, bus, device, function); + if (rc < 0) { + demu_teardown(); + exit(1); + } + + pfd.fd = xc_evtchn_fd(demu_state.xceh); + pfd.events = POLLIN | POLLERR | POLLHUP; + pfd.revents = 0; + + for (;;) { + rc = poll(&pfd, 1, 5000); + + if (rc > 0 && pfd.revents & POLLIN) + demu_poll_iopages(); + + if (rc < 0 && errno != EINTR) + break; + } + + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * c-tab-always-indent: nil + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/main.c b/main.c deleted file mode 100644 index cbb833f..0000000 --- a/main.c +++ /dev/null @@ -1,829 +0,0 @@ -/* - * Copyright (c) 2012, Citrix Systems Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS - * "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 COPYRIGHT - * HOLDER OR CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "debug.h" -#include "device.h" -#include "pci.h" - -#define FALSE 0 - -#define mb() asm volatile ("" : : : "memory") - -enum { - DEMU_OPT_DOMAIN, - DEMU_OPT_VCPUS, - DEMU_OPT_BUS, - DEMU_OPT_DEVICE, - DEMU_OPT_FUNCTION, - DEMU_NR_OPTS - }; - -static struct option demu_option[] = { - {"domain", 1, NULL, 0}, - {"vcpus", 1, NULL, 0}, - {"bus", 1, NULL, 0}, - {"device", 1, NULL, 0}, - {"function", 1, NULL, 0}, - {NULL, 0, NULL, 0} -}; - -static const char *demu_option_text[] = { - "", - "", - "", - "", - "", - NULL -}; - -static const char *prog; - -static void -usage(void) -{ - int i; - - fprintf(stderr, "Usage: %s \n\n", prog); - - for (i = 0; i < DEMU_NR_OPTS; i++) - fprintf(stderr, "\t--%s %s\n", - demu_option[i].name, - demu_option_text[i]); - - fprintf(stderr, "\n"); - - exit(2); -} - -typedef enum { - DEMU_SEQ_UNINITIALIZED = 0, - DEMU_SEQ_INTERFACE_OPEN, - DEMU_SEQ_SERVER_REGISTERED, - DEMU_SEQ_SHARED_IOPAGE_MAPPED, - DEMU_SEQ_BUFFERED_IOPAGE_MAPPED, - DEMU_SEQ_PORT_ARRAY_ALLOCATED, - DEMU_SEQ_EVTCHN_OPEN, - DEMU_SEQ_PORTS_BOUND, - DEMU_SEQ_BUF_PORT_BOUND, - DEMU_SEQ_INITIALIZED, - DEMU_NR_SEQS -} demu_seq_t; - -typedef struct demu_state { - demu_seq_t seq; - xc_interface *xch; - xc_interface *xceh; - domid_t domid; - unsigned int vcpus; - ioservid_t ioservid; - shared_iopage_t *iopage; - evtchn_port_t *ioreq_local_port; - buffered_iopage_t *buffered_iopage; - evtchn_port_t buf_ioreq_port; - evtchn_port_t buf_ioreq_local_port; -} demu_state_t; - -static demu_state_t demu_state; - -static void -handle_pio(ioreq_t *ioreq) -{ - if (ioreq->dir == IOREQ_READ) { - if (!ioreq->data_is_ptr) { - ioreq->data = (uint64_t)pci_bar_read(0, ioreq->addr, ioreq->size); - } else { - assert(FALSE); - } - } else if (ioreq->dir == IOREQ_WRITE) { - if (!ioreq->data_is_ptr) { - pci_bar_write(0, ioreq->addr, ioreq->size, (uint32_t)ioreq->data); - } else { - assert(FALSE); - } - } -} - -static void -handle_copy(ioreq_t *ioreq) -{ - if (ioreq->dir == IOREQ_READ) { - if (!ioreq->data_is_ptr) { - ioreq->data = (uint64_t)pci_bar_read(1, ioreq->addr, ioreq->size); - } else { - assert(FALSE); - } - } else if (ioreq->dir == IOREQ_WRITE) { - if (!ioreq->data_is_ptr) { - pci_bar_write(1, ioreq->addr, ioreq->size, (uint32_t)ioreq->data); - } else { - assert(FALSE); - } - } -} - -static void -handle_pci_config(ioreq_t *ioreq) -{ - if (ioreq->dir == IOREQ_READ) { - if (!ioreq->data_is_ptr) { - ioreq->data = (uint32_t)pci_config_read(ioreq->addr, ioreq->size); - } else { - assert(FALSE); - } - } else if (ioreq->dir == IOREQ_WRITE) { - if (!ioreq->data_is_ptr) { - pci_config_write(ioreq->addr, ioreq->size, (uint32_t)ioreq->data); - } else { - assert(FALSE); - } - } -} - -static void -handle_ioreq(ioreq_t *ioreq) -{ - switch (ioreq->type) { - case IOREQ_TYPE_PIO: - handle_pio(ioreq); - break; - - case IOREQ_TYPE_COPY: - handle_copy(ioreq); - break; - - case IOREQ_TYPE_PCI_CONFIG: - handle_pci_config(ioreq); - break; - - case IOREQ_TYPE_TIMEOFFSET: - break; - - case IOREQ_TYPE_INVALIDATE: - break; - - default: - DBG("UNKNOWN (%02x)", ioreq->type); - break; - } -} - -static void -demu_seq_next(void) -{ - assert(demu_state.seq < DEMU_SEQ_INITIALIZED); - - switch (++demu_state.seq) { - case DEMU_SEQ_INTERFACE_OPEN: - DBG(">INTERFACE_OPEN\n"); - break; - - case DEMU_SEQ_SERVER_REGISTERED: - DBG(">SERVER_REGISTERED\n"); - DBG("ioservid = %u\n", demu_state.ioservid); - break; - - case DEMU_SEQ_SHARED_IOPAGE_MAPPED: - DBG(">SHARED_IOPAGE_MAPPED\n"); - DBG("iopage = %p\n", demu_state.iopage); - break; - - case DEMU_SEQ_BUFFERED_IOPAGE_MAPPED: - DBG(">BUFFERED_IOPAGE_MAPPED\n"); - DBG("buffered_iopage = %p\n", demu_state.buffered_iopage); - break; - - case DEMU_SEQ_PORT_ARRAY_ALLOCATED: - DBG(">PORT_ARRAY_ALLOCATED\n"); - break; - - case DEMU_SEQ_EVTCHN_OPEN: - DBG(">EVTCHN_OPEN\n"); - break; - - case DEMU_SEQ_PORTS_BOUND: { - int i; - - DBG(">EVTCHN_PORTS_BOUND\n"); - - for (i = 0; i < demu_state.vcpus; i++) - DBG("VCPU%d: %u -> %u\n", i, - demu_state.iopage->vcpu_ioreq[i].vp_eport, - demu_state.ioreq_local_port[i]); - - break; - } - - case DEMU_SEQ_BUF_PORT_BOUND: - DBG(">EVTCHN_BUF_PORT_BOUND\n"); - - DBG("%u -> %u\n", - demu_state.buf_ioreq_port, - demu_state.buf_ioreq_local_port); - break; - - case DEMU_SEQ_INITIALIZED: - DBG(">INITIALIZED\n"); - break; - - default: - assert(FALSE); - break; - } -} - -static void -demu_teardown(void) -{ - if (demu_state.seq == DEMU_SEQ_INITIALIZED) { - DBG("= DEMU_SEQ_PORTS_BOUND) { - DBG("= DEMU_SEQ_PORTS_BOUND) { - DBG("= DEMU_SEQ_EVTCHN_OPEN) { - int i; - - DBG("= 0) { - DBG("VCPU%d: %u\n", i, port); - (void) xc_evtchn_unbind(demu_state.xceh, port); - } - } - - xc_evtchn_close(demu_state.xceh); - - demu_state.seq = DEMU_SEQ_PORT_ARRAY_ALLOCATED; - } - - if (demu_state.seq >= DEMU_SEQ_PORT_ARRAY_ALLOCATED) { - DBG("= DEMU_SEQ_BUFFERED_IOPAGE_MAPPED) { - DBG("= DEMU_SEQ_SHARED_IOPAGE_MAPPED) { - DBG("= DEMU_SEQ_SERVER_REGISTERED) { - DBG("= DEMU_SEQ_INTERFACE_OPEN) { - DBG("vcpu_ioreq[i].vp_eport; - - rc = xc_evtchn_bind_interdomain(demu_state.xceh, demu_state.domid, - port); - if (rc < 0) - goto fail10; - - demu_state.ioreq_local_port[i] = rc; - } - - demu_seq_next(); - - rc = xc_hvm_get_ioreq_server_buf_port(demu_state.xch, demu_state.domid, - demu_state.ioservid, &port); - if (rc < 0) - goto fail11; - - rc = xc_evtchn_bind_interdomain(demu_state.xceh, demu_state.domid, - port); - if (rc < 0) - goto fail12; - - demu_state.buf_ioreq_local_port = rc; - - demu_seq_next(); - - rc = device_initialize(demu_state.xch, demu_state.domid, - demu_state.ioservid, bus, device, function); - if (rc < 0) - goto fail13; - - demu_seq_next(); - - assert(demu_state.seq == DEMU_SEQ_INITIALIZED); - return 0; - -fail13: - DBG("fail13\n"); - -fail12: - DBG("fail12\n"); - -fail11: - DBG("fail11\n"); - -fail10: - DBG("fail10\n"); - -fail9: - DBG("fail9\n"); - -fail8: - DBG("fail8\n"); - -fail7: - DBG("fail7\n"); - -fail6: - DBG("fail6\n"); - -fail5: - DBG("fail5\n"); - -fail4: - DBG("fail4\n"); - -fail3: - DBG("fail3\n"); - -fail2: - DBG("fail2\n"); - -fail1: - DBG("fail1\n"); - - warn("fail"); - return -1; -} - -static void -demu_poll_buffered_iopage(void) -{ - if (demu_state.seq != DEMU_SEQ_INITIALIZED) - return; - - for (;;) { - unsigned int read_pointer; - unsigned int write_pointer; - - read_pointer = demu_state.buffered_iopage->read_pointer; - write_pointer = demu_state.buffered_iopage->write_pointer; - - if (read_pointer == write_pointer) - break; - - while (read_pointer != write_pointer) { - unsigned int slot; - buf_ioreq_t *buf_ioreq; - ioreq_t ioreq; - - slot = read_pointer % IOREQ_BUFFER_SLOT_NUM; - - buf_ioreq = &demu_state.buffered_iopage->buf_ioreq[slot]; - - ioreq.size = 1UL << buf_ioreq->size; - ioreq.count = 1; - ioreq.addr = buf_ioreq->addr; - ioreq.data = buf_ioreq->data; - ioreq.state = STATE_IOREQ_READY; - ioreq.dir = buf_ioreq->dir; - ioreq.df = 1; - ioreq.type = buf_ioreq->type; - ioreq.data_is_ptr = 0; - - read_pointer++; - - if (ioreq.size == 8) { - slot = read_pointer % IOREQ_BUFFER_SLOT_NUM; - buf_ioreq = &demu_state.buffered_iopage->buf_ioreq[slot]; - - ioreq.data |= ((uint64_t)buf_ioreq->data) << 32; - - read_pointer++; - } - - handle_ioreq(&ioreq); - mb(); - } - - demu_state.buffered_iopage->read_pointer = read_pointer; - mb(); - } -} - -static void -demu_poll_iopage(unsigned int i) -{ - ioreq_t *ioreq; - - if (demu_state.seq != DEMU_SEQ_INITIALIZED) - return; - - ioreq = &demu_state.iopage->vcpu_ioreq[i]; - if (ioreq->state != STATE_IOREQ_READY) { - fprintf(stderr, "IO request not ready\n"); - return; - } - mb(); - - ioreq->state = STATE_IOREQ_INPROCESS; - - handle_ioreq(ioreq); - mb(); - - ioreq->state = STATE_IORESP_READY; - mb(); - - xc_evtchn_notify(demu_state.xceh, demu_state.ioreq_local_port[i]); -} - -static void -demu_poll_iopages(void) -{ - evtchn_port_t port; - int i; - - if (demu_state.seq != DEMU_SEQ_INITIALIZED) - return; - - port = xc_evtchn_pending(demu_state.xceh); - if (port < 0) - return; - - if (port == demu_state.buf_ioreq_local_port) { - xc_evtchn_unmask(demu_state.xceh, port); - demu_poll_buffered_iopage(); - } else { - for (i = 0; i < demu_state.vcpus; i++) { - if (port == demu_state.ioreq_local_port[i]) { - xc_evtchn_unmask(demu_state.xceh, port); - demu_poll_iopage(i); - } - } - } -} - -int -main(int argc, char **argv, char **envp) -{ - char *domain_str; - char *vcpus_str; - char *bus_str; - char *device_str; - char *function_str; - int index; - char *end; - domid_t domid; - unsigned int vcpus; - unsigned int bus; - unsigned int device; - unsigned int function; - sigset_t block; - struct pollfd pfd; - int rc; - - prog = basename(argv[0]); - - domain_str = NULL; - vcpus_str = NULL; - bus_str = NULL; - device_str = NULL; - function_str = NULL; - - for (;;) { - char c; - - c = getopt_long(argc, argv, "", demu_option, &index); - if (c == -1) - break; - - DBG("--%s = '%s'\n", demu_option[index].name, optarg); - - assert(c == 0); - switch (index) { - case DEMU_OPT_DOMAIN: - domain_str = optarg; - break; - - case DEMU_OPT_VCPUS: - vcpus_str = optarg; - break; - - case DEMU_OPT_BUS: - bus_str = optarg; - break; - - case DEMU_OPT_DEVICE: - device_str = optarg; - break; - - case DEMU_OPT_FUNCTION: - function_str = optarg; - break; - - default: - assert(FALSE); - break; - } - } - - if (domain_str == NULL || - vcpus_str == NULL || - bus_str == NULL || - device_str == NULL || - function_str == NULL) { - usage(); - /*NOTREACHED*/ - } - - domid = (domid_t)strtol(domain_str, &end, 0); - if (*end != '\0') { - fprintf(stderr, "invalid domain '%s'\n", domain_str); - exit(1); - } - - vcpus = (unsigned int)strtol(vcpus_str, &end, 0); - if (*end != '\0') { - fprintf(stderr, "invalid vcpu count '%s'\n", vcpus_str); - exit(1); - } - - bus = (unsigned int)strtol(bus_str, &end, 0); - if (*end != '\0') { - fprintf(stderr, "invalid bus '%s'\n", bus_str); - exit(1); - } - - device = (unsigned int)strtol(device_str, &end, 0); - if (*end != '\0') { - fprintf(stderr, "invalid vcpu count '%s'\n", device_str); - exit(1); - } - - function = (unsigned int)strtol(function_str, &end, 0); - if (*end != '\0') { - fprintf(stderr, "invalid vcpu count '%s'\n", function_str); - exit(1); - } - - sigfillset(&block); - - memset(&sigterm_handler, 0, sizeof (struct sigaction)); - sigterm_handler.sa_handler = demu_sigterm; - - sigaction(SIGTERM, &sigterm_handler, NULL); - sigdelset(&block, SIGTERM); - - sigaction(SIGINT, &sigterm_handler, NULL); - sigdelset(&block, SIGINT); - - sigaction(SIGHUP, &sigterm_handler, NULL); - sigdelset(&block, SIGHUP); - - sigaction(SIGABRT, &sigterm_handler, NULL); - sigdelset(&block, SIGABRT); - - memset(&sigusr1_handler, 0, sizeof (struct sigaction)); - sigusr1_handler.sa_handler = demu_sigusr1; - - sigaction(SIGUSR1, &sigusr1_handler, NULL); - sigdelset(&block, SIGUSR1); - - sigprocmask(SIG_BLOCK, &block, NULL); - - rc = demu_initialize(domid, vcpus, bus, device, function); - if (rc < 0) { - demu_teardown(); - exit(1); - } - - pfd.fd = xc_evtchn_fd(demu_state.xceh); - pfd.events = POLLIN | POLLERR | POLLHUP; - pfd.revents = 0; - - for (;;) { - rc = poll(&pfd, 1, 5000); - - if (rc > 0 && pfd.revents & POLLIN) - demu_poll_iopages(); - - if (rc < 0 && errno != EINTR) - break; - } - - return 0; -} - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * c-tab-always-indent: nil - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */