diff options
Diffstat (limited to 'tools/xcs/ctrl_interface.c')
-rw-r--r-- | tools/xcs/ctrl_interface.c | 269 |
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); +} |