aboutsummaryrefslogtreecommitdiffstats
path: root/tools/xcs/ctrl_interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/xcs/ctrl_interface.c')
-rw-r--r--tools/xcs/ctrl_interface.c269
1 files changed, 269 insertions, 0 deletions
diff --git a/tools/xcs/ctrl_interface.c b/tools/xcs/ctrl_interface.c
new file mode 100644
index 0000000000..0896910cb4
--- /dev/null
+++ b/tools/xcs/ctrl_interface.c
@@ -0,0 +1,269 @@
+/* control_interface.c
+ *
+ * Interfaces to control message rings to VMs.
+ *
+ * Most of this is directly based on the original xu interface to python
+ * written by Keir Fraser.
+ *
+ * (c) 2004, Andrew Warfield
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include "xcs.h"
+
+static int xc_handle = -1;
+
+/* Called at start-of-day when using the control channel interface. */
+int ctrl_chan_init(void)
+{
+ if ( (xc_handle = xc_interface_open()) == -1 )
+ {
+ DPRINTF("Could not open Xen control interface");
+ return -1;
+ }
+
+ return 0;
+}
+
+static control_if_t *map_control_interface(int fd, unsigned long pfn,
+ u32 dom)
+{
+ char *vaddr = xc_map_foreign_range( fd, dom, PAGE_SIZE,
+ PROT_READ|PROT_WRITE, pfn );
+ if ( vaddr == NULL )
+ return NULL;
+ return (control_if_t *)(vaddr + 2048);
+}
+
+static void unmap_control_interface(int fd, control_if_t *c)
+{
+ char *vaddr = (char *)c - 2048;
+ (void)munmap(vaddr, PAGE_SIZE);
+}
+
+int ctrl_chan_notify(control_channel_t *cc)
+{
+ return xc_evtchn_send(xc_handle, cc->local_port);
+}
+
+int ctrl_chan_read_request(control_channel_t *cc, xcs_control_msg_t *dmsg)
+{
+ control_msg_t *smsg;
+ RING_IDX c = cc->tx_ring.req_cons;
+
+ if ( !RING_HAS_UNCONSUMED_REQUESTS(CTRL_RING, &cc->tx_ring) )
+ {
+ DPRINTF("no request to read\n");
+ return -1;
+ }
+
+ rmb(); /* make sure we see the data associated with the request */
+ smsg = RING_GET_REQUEST(CTRL_RING, &cc->tx_ring, c);
+ memcpy(&dmsg->msg, smsg, sizeof(*smsg));
+ if ( dmsg->msg.length > sizeof(dmsg->msg.msg) )
+ dmsg->msg.length = sizeof(dmsg->msg.msg);
+ cc->tx_ring.req_cons++;
+ return 0;
+}
+
+int ctrl_chan_write_request(control_channel_t *cc,
+ xcs_control_msg_t *smsg)
+{
+ control_msg_t *dmsg;
+ RING_IDX p = cc->rx_ring.req_prod_pvt;
+
+ if ( RING_FULL(CTRL_RING, &cc->rx_ring) )
+ {
+ DPRINTF("no space to write request");
+ return -ENOSPC;
+ }
+
+ dmsg = RING_GET_REQUEST(CTRL_RING, &cc->rx_ring, p);
+ memcpy(dmsg, &smsg->msg, sizeof(*dmsg));
+
+ wmb();
+ cc->rx_ring.req_prod_pvt++;
+ RING_PUSH_REQUESTS(CTRL_RING, &cc->rx_ring);
+
+ return 0;
+}
+
+int ctrl_chan_read_response(control_channel_t *cc, xcs_control_msg_t *dmsg)
+{
+ control_msg_t *smsg;
+ RING_IDX c = cc->rx_ring.rsp_cons;
+
+ if ( !RING_HAS_UNCONSUMED_RESPONSES(CTRL_RING, &cc->rx_ring) )
+ {
+ DPRINTF("no response to read");
+ return -1;
+ }
+
+ rmb(); /* make sure we see the data associated with the request */
+ smsg = RING_GET_RESPONSE(CTRL_RING, &cc->rx_ring, c);
+ memcpy(&dmsg->msg, smsg, sizeof(*smsg));
+ if ( dmsg->msg.length > sizeof(dmsg->msg.msg) )
+ dmsg->msg.length = sizeof(dmsg->msg.msg);
+ cc->rx_ring.rsp_cons++;
+ return 0;
+}
+
+int ctrl_chan_write_response(control_channel_t *cc,
+ xcs_control_msg_t *smsg)
+{
+ control_msg_t *dmsg;
+ RING_IDX p = cc->tx_ring.rsp_prod_pvt;
+
+ /* akw: if the ring is synchronous, you should never need this test! */
+ /* (but it was in the original code... ) */
+ if ( cc->tx_ring.req_cons == cc->tx_ring.rsp_prod_pvt )
+ {
+ DPRINTF("no space to write response");
+ return -ENOSPC;
+ }
+
+ dmsg = RING_GET_RESPONSE(CTRL_RING, &cc->tx_ring, p);
+ memcpy(dmsg, &smsg->msg, sizeof(*dmsg));
+
+ wmb();
+ cc->tx_ring.rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(CTRL_RING, &cc->tx_ring);
+
+ return 0;
+}
+
+int ctrl_chan_request_to_read(control_channel_t *cc)
+{
+ return (RING_HAS_UNCONSUMED_REQUESTS(CTRL_RING, &cc->tx_ring));
+}
+
+int ctrl_chan_space_to_write_request(control_channel_t *cc)
+{
+ return (!(RING_FULL(CTRL_RING, &cc->rx_ring)));
+}
+
+int ctrl_chan_response_to_read(control_channel_t *cc)
+{
+ return (RING_HAS_UNCONSUMED_RESPONSES(CTRL_RING, &cc->rx_ring));
+}
+
+int ctrl_chan_space_to_write_response(control_channel_t *cc)
+{
+ /* again, there is something fishy here. */
+ return ( cc->tx_ring.req_cons != cc->tx_ring.rsp_prod_pvt );
+}
+
+int ctrl_chan_connect(control_channel_t *cc)
+{
+ xc_dominfo_t info;
+
+ if ( cc->connected )
+ {
+ return 0;
+ }
+
+ if ( (xc_domain_getinfo(xc_handle, cc->remote_dom, 1, &info) != 1) ||
+ (info.domid != cc->remote_dom) )
+ {
+ DPRINTF("Failed to obtain domain status");
+ return -1;
+ }
+
+ cc->interface =
+ map_control_interface(xc_handle, info.shared_info_frame,
+ cc->remote_dom);
+
+ if ( cc->interface == NULL )
+ {
+ DPRINTF("Failed to map domain control interface");
+ return -1;
+ }
+
+ /* Synchronise ring indexes. */
+ BACK_RING_ATTACH(CTRL_RING, &cc->tx_ring, &cc->interface->tx_ring);
+ FRONT_RING_ATTACH(CTRL_RING, &cc->rx_ring, &cc->interface->rx_ring);
+
+ cc->connected = 1;
+
+ return 0;
+}
+
+void ctrl_chan_disconnect(control_channel_t *cc)
+{
+ if ( cc->connected )
+ unmap_control_interface(xc_handle, cc->interface);
+ cc->connected = 0;
+}
+
+
+control_channel_t *ctrl_chan_new(u32 dom, int local_port, int remote_port)
+{
+ control_channel_t *cc;
+
+ cc = (control_channel_t *)malloc(sizeof(control_channel_t));
+ if ( cc == NULL ) return NULL;
+
+ cc->connected = 0;
+ cc->remote_dom = dom;
+
+ if ( dom == 0 )
+ {
+ /*
+ * The control-interface event channel for DOM0 is already set up.
+ * We use an ioctl to discover the port at our end of the channel.
+ */
+ local_port = ioctl(xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN,
+ NULL);
+ remote_port = -1; /* We don't need the remote end of the DOM0 link. */
+ if ( local_port < 0 )
+ {
+ DPRINTF("Could not open channel to DOM0");
+ goto fail;
+ }
+ }
+ else if ( xc_evtchn_bind_interdomain(xc_handle,
+ DOMID_SELF, dom,
+ &local_port, &remote_port) != 0 )
+ {
+ DPRINTF("Could not open channel to domain");
+ goto fail;
+ }
+
+ cc->local_port = local_port;
+ cc->remote_port = remote_port;
+
+ if ( ctrl_chan_connect(cc) != 0 )
+ goto fail;
+
+ return cc;
+
+ fail:
+ if ( dom != 0 )
+ (void)xc_evtchn_close(xc_handle, DOMID_SELF, local_port);
+
+ free(cc);
+
+ return NULL;
+}
+
+void ctrl_chan_free(control_channel_t *cc)
+{
+ ctrl_chan_disconnect(cc);
+ if ( cc->remote_dom != 0 )
+ (void)xc_evtchn_close(xc_handle, DOMID_SELF, cc->local_port);
+ free(cc);
+}
+
+
+/* other libxc commands: */
+
+int ctrl_chan_bind_virq(int virq, int *port)
+{
+ return xc_evtchn_bind_virq(xc_handle, virq, port);
+}