Esempio n. 1
0
static NTSTATUS
v2v_disconnect_supplicant(const struct v2v_channel *_channel)
{
    NTSTATUS status;
    struct v2v_channel *channel = (struct v2v_channel *)_channel;

    v2v_xenops_grant_unmap((void *)channel->cons_sring, channel->u.supplicant.prod_detail);
    v2v_xenops_grant_unmap(channel->prod_sring, channel->u.supplicant.cons_detail);
    v2v_xenops_grant_unmap(channel->control, channel->u.supplicant.control_detail);
    channel->u.supplicant.prod_detail = NULL;
    channel->u.supplicant.cons_detail = NULL;
    channel->u.supplicant.control_detail = NULL;
    channel->prod_sring = NULL;
    channel->cons_sring = NULL;
    channel->control = NULL;

    if (!is_null_EVTCHN_PORT(channel->receive_evtchn_port)) {
        EvtchnClose(channel->receive_evtchn_port);
        channel->receive_evtchn_port = null_EVTCHN_PORT();
    }
    if (!is_null_EVTCHN_PORT(channel->send_evtchn_port)) {
        EvtchnClose(channel->send_evtchn_port);
        channel->send_evtchn_port = null_EVTCHN_PORT();
    }

    status = v2v_change_local_state(channel, XBT_NIL, v2v_state_disconnected);
    if (!NT_SUCCESS(status))
        return status;
    
    v2v_destroy_channel(channel, FALSE);

    return STATUS_SUCCESS;
}
Esempio n. 2
0
static NTSTATUS
V4vInitializeEventChannel(PDEVICE_OBJECT fdo)
{
    XENV4V_EXTENSION   *pde = V4vGetDeviceExtension(fdo);
    KLOCK_QUEUE_HANDLE  lqh;

    KeAcquireInStackQueuedSpinLock(&pde->virqLock, &lqh);

    if (!is_null_EVTCHN_PORT(pde->virqPort)) {
        KeReleaseInStackQueuedSpinLock(&lqh);
        TraceWarning(("V4V VIRQ already bound?\n"));
	    return STATUS_SUCCESS;
    }

    pde->virqPort = EvtchnBindVirq(VIRQ_V4V, V4vVirqNotifyIsr, fdo);
    if (is_null_EVTCHN_PORT(pde->virqPort)) {
        KeReleaseInStackQueuedSpinLock(&lqh);
        TraceError(("failed to bind V4V VIRQ\n"));
	    return STATUS_INSUFFICIENT_RESOURCES;
    }

    KeReleaseInStackQueuedSpinLock(&lqh);

    TraceNotice(("V4V VIRQ connected.\n"));

    return STATUS_SUCCESS;
}
Esempio n. 3
0
static void
v2v_destroy_channel(const struct v2v_channel *_chan, BOOLEAN free_temple)
{
    struct v2v_channel *chan = (struct v2v_channel *)_chan;
    unsigned x;

    if (chan->remote_state_watch)
        xenbus_unregister_watch(chan->remote_state_watch);
    if (chan->local_prefix)
        ExFreePoolWithTag(chan->local_prefix, V2V_TAG);
    if (chan->remote_prefix)
		ExFreePoolWithTag(chan->remote_prefix, V2V_TAG);
    
    if (!chan->is_temple) {
        v2v_xenops_grant_unmap((void *)chan->cons_sring, chan->u.supplicant.prod_detail);
        v2v_xenops_grant_unmap(chan->prod_sring, chan->u.supplicant.cons_detail);
        v2v_xenops_grant_unmap(chan->control, chan->u.supplicant.control_detail);
    }
    else if (free_temple) { /* and is temple */
        if (chan->u.temple.grant_cache) {
            for (x = 0; x < chan->nr_prod_ring_pages; x++) {
                if (!is_null_GRANT_REF(chan->u.temple.prod_grefs[x]))
                    GnttabEndForeignAccessCache(chan->u.temple.prod_grefs[x],
                                                chan->u.temple.grant_cache);
            }
            for (x = 0; x < chan->nr_cons_ring_pages; x++) {
                if (!is_null_GRANT_REF(chan->u.temple.cons_grefs[x]))
                    GnttabEndForeignAccessCache(chan->u.temple.cons_grefs[x],
                                                chan->u.temple.grant_cache);
            }

            if (!is_null_GRANT_REF(chan->u.temple.control_gref))
                GnttabEndForeignAccessCache(chan->u.temple.control_gref,
                                            chan->u.temple.grant_cache);
            
            GnttabFreeCache(chan->u.temple.grant_cache);
        }
            
        if (chan->prod_sring)
            ExFreePoolWithTag(chan->prod_sring, V2V_TAG);
        if (chan->cons_sring)
            ExFreePoolWithTag((void*)chan->cons_sring, V2V_TAG);                
        if (chan->control)
            ExFreePoolWithTag(chan->control, V2V_TAG);
    }

    if (!is_null_EVTCHN_PORT(chan->receive_evtchn_port))
        EvtchnClose(chan->receive_evtchn_port);
    if (!is_null_EVTCHN_PORT(chan->send_evtchn_port))
        EvtchnClose(chan->send_evtchn_port);

    EvtchnReleaseDebugCallback(chan->debug_callback);

    ExFreePoolWithTag(chan, V2V_TAG);
}
Esempio n. 4
0
VOID
XenLowerFree(
    PXEN_LOWER XenLower)
{
    if (!XenLower)
    {
        return;
    }

    if (XenLower->LateSuspendHandler)
    {
        EvtchnUnregisterSuspendHandler(XenLower->LateSuspendHandler);
    }

    if (!is_null_EVTCHN_PORT(XenLower->EvtchnPort))
    {
        EvtchnPortStop(XenLower->EvtchnPort);
        EvtchnClose(XenLower->EvtchnPort);
    }

    if (!is_null_GRANT_REF(XenLower->SringGrantRef))
    {
        (VOID)GnttabEndForeignAccess(XenLower->SringGrantRef);
    }

    ExFreePool(XenLower);
}
Esempio n. 5
0
static void
close_evtchn(struct scsifilt *sf)
{
    if (!is_null_EVTCHN_PORT(sf->evtchn_port))
        EvtchnClose(sf->evtchn_port);
    sf->evtchn_port = null_EVTCHN_PORT();
}
Esempio n. 6
0
VOID
XenLowerScheduleEvtChnDPC(
    PXEN_LOWER XenLower)
{
    if (!is_null_EVTCHN_PORT(XenLower->EvtchnPort))
    {
        EvtchnRaiseLocally(XenLower->EvtchnPort);
    }
}
Esempio n. 7
0
NTSTATUS
v2v_nc2_prep_message(struct v2v_channel *channel,
                     size_t msg_size,
                     unsigned char type,
                     unsigned char flags,
                     volatile void **payload)
{
    volatile struct netchannel2_msg_hdr *hdr;
    unsigned short size;
    unsigned short rounded_size;

    XM_ASSERT(channel != NULL);
    XM_ASSERT(payload != NULL);

    msg_size += sizeof(*hdr);
    if ( ((msg_size + 7) & ~7) >
         channel->nc2_rings.producer_payload_bytes )
        return STATUS_INVALID_PARAMETER;

    if (type >= NETCHANNEL2_MSG_PAD)
        return STATUS_NOT_IMPLEMENTED;

    size = (unsigned short)msg_size;
    rounded_size = (size + 7) & ~7;

    if (channel->nc2_rings.remote_endpoint->consumer_active)
        v2v_nc2_send_messages(channel);
    if (!nc2_can_send_payload_bytes(&channel->nc2_rings, rounded_size)) {
        if (channel->is_sync)
            KeResetEvent(&channel->s.sync.send_event);
        if (!nc2_can_send_payload_bytes(&channel->nc2_rings, rounded_size))
            return STATUS_RETRY;
        if (channel->is_sync)
            KeSetEvent(&channel->s.sync.send_event, IO_NO_INCREMENT, FALSE);
    }
    __nc2_avoid_ring_wrap(&channel->nc2_rings, rounded_size);
    hdr = __nc2_get_message_ptr(&channel->nc2_rings);
    hdr->size = size;
    hdr->type = type;
    hdr->flags = flags;
    *payload = hdr + 1;
    channel->nc2_rings.local_prod_pvt += rounded_size;
    channel->nc2_rings.local_prod_bytes_available -= rounded_size;

    if (channel->nc2_rings.remote_endpoint->consumer_active &&
        !channel->nc2_rings.local_producer_active &&
        __nc2_flush_would_trigger_event(&channel->nc2_rings)) {
        channel->nc2_rings.local_endpoint->producer_active = 1;
        channel->nc2_rings.local_producer_active = 1;
        XM_ASSERT(!is_null_EVTCHN_PORT(channel->send_evtchn_port));
        EvtchnNotifyRemote(channel->send_evtchn_port);
    }

    return STATUS_SUCCESS;
}
Esempio n. 8
0
VOID
XenLowerDisconnectEvtChnDPC(
    PXEN_LOWER XenLower)
{
    if (!is_null_EVTCHN_PORT(XenLower->EvtchnPort))
    {
        EvtchnPortStop(XenLower->EvtchnPort);
        EvtchnClose(XenLower->EvtchnPort);
        XenLower->EvtchnPort = null_EVTCHN_PORT();
    }
}
Esempio n. 9
0
void
v2v_nc2_finish_message(struct v2v_channel *channel)
{
    XM_ASSERT(channel != NULL);

    channel->nc2_rings.local_cons_pvt +=
        (channel->current_message_size + sizeof(struct netchannel2_msg_hdr) + 7) & ~7;
    if (nc2_finish_messages(&channel->nc2_rings)) {
        XM_ASSERT(!is_null_EVTCHN_PORT(channel->receive_evtchn_port));
        EvtchnNotifyRemote(channel->receive_evtchn_port);
    }
}
Esempio n. 10
0
static NTSTATUS
open_evtchn(struct scsifilt *sf)
{
    DOMAIN_ID domid = sf->backend_domid;

    close_evtchn(sf);
    sf->evtchn_port = EvtchnAllocUnbound(domid, handle_evtchn, sf);
    if (is_null_EVTCHN_PORT(sf->evtchn_port))
        return STATUS_INSUFFICIENT_RESOURCES;
    else
        return STATUS_SUCCESS;
}
Esempio n. 11
0
NTSTATUS
XenLowerEvtChnNotify(
    PVOID Context)
{
    PXEN_LOWER XenLower = (PXEN_LOWER)Context;

    if (is_null_EVTCHN_PORT(XenLower->EvtchnPort))
    {
        TraceError((__FUNCTION__ ": no event channel port, cannot notory anything.\n"));
        return STATUS_UNSUCCESSFUL;
    }

    EvtchnNotifyRemote(XenLower->EvtchnPort);

    return STATUS_SUCCESS;
}
Esempio n. 12
0
BOOLEAN
XenLowerConnectEvtChnDPC(
    PXEN_LOWER XenLower,
    PEVTCHN_HANDLER_CB DpcCallback,
    VOID *Context)
{
    XenLower->EvtchnPort =
        EvtchnAllocUnboundDpc(XenLower->BackendDomid, DpcCallback, Context);

    if (is_null_EVTCHN_PORT(XenLower->EvtchnPort))
    {
        TraceError((__FUNCTION__ ": failed to allocate DPC for Event Channel.\n"));
        return FALSE;
    }

    return TRUE;
}
Esempio n. 13
0
void
v2v_nc2_send_messages(struct v2v_channel *channel)
{
    XM_ASSERT(channel != NULL);

    if (nc2_flush_ring(&channel->nc2_rings)) {
        /* The read of consumer_spinning needs to be after the read of
         * prod_event in nc2_flush_ring().  Both fields are volatile,
         * so the compiler gives us that for free and we don't need
         * explicit barriers. */
        if (!channel->nc2_rings.remote_endpoint->consumer_spinning) {
            XM_ASSERT(!is_null_EVTCHN_PORT(channel->send_evtchn_port));
            EvtchnNotifyRemote(channel->send_evtchn_port);            
        }
        if (channel->nc2_rings.local_producer_active) {
            channel->nc2_rings.local_producer_active = 0;
            channel->nc2_rings.local_endpoint->producer_active = 0;
        }
    }
}
Esempio n. 14
0
static VOID
V4vUninitializeEventChannel(PDEVICE_OBJECT fdo)
{
    XENV4V_EXTENSION   *pde = V4vGetDeviceExtension(fdo);
    KLOCK_QUEUE_HANDLE  lqh;

    KeAcquireInStackQueuedSpinLock(&pde->virqLock, &lqh);

    if (is_null_EVTCHN_PORT(pde->virqPort)) {
        // This is ok, e.g. getting a stop and remove PnP call
        KeReleaseInStackQueuedSpinLock(&lqh);
	    return;
    }

    EvtchnClose(pde->virqPort);
    pde->virqPort = null_EVTCHN_PORT();

    KeReleaseInStackQueuedSpinLock(&lqh);

    TraceNotice(("V4V VIRQ disconnected.\n"));
}
Esempio n. 15
0
NTSTATUS
v2v_connect(const char *xenbus_prefix, struct v2v_channel **channel,
            struct v2v_async *async_values)
{
    NTSTATUS status = STATUS_SUCCESS;
    xenbus_transaction_t xbt = {0};
    struct v2v_channel *chan;
    enum v2v_endpoint_state remote_state;
    int producer_ring_order;
    int consumer_ring_order;
    int x;    
    BOOLEAN xbt_pending = FALSE;

    XM_ASSERT(channel != NULL);
    XM_ASSERT(xenbus_prefix != NULL);

    if (async_values && 
       (!async_values->receive_dpc || !async_values->send_dpc))
        return STATUS_INVALID_PARAMETER;

    *channel = NULL;

    for (;;) {
        chan = v2v_make_channel(xenbus_prefix, async_values);
        if (!chan)
            return STATUS_NO_MEMORY;

        xenbus_transaction_start(&xbt);
        xbt_pending = TRUE;

        status = v2v_connect_channel_xenbus(chan, xbt);
        if (!NT_SUCCESS(status))
            goto err; 

        status = v2v_get_remote_state_internal(xbt, chan, &remote_state);
        if (remote_state == v2v_state_unknown)
            goto err; /* status set to error code */
        if (remote_state != v2v_state_listening) {
            status = STATUS_NO_SUCH_DEVICE;
            goto err;
        }
    
        status = 
            v2v_xenstore_gather(xbt, chan->remote_prefix,
                             "prod-order",
                                 xenstore_gather_type_int,
                                 &producer_ring_order,
                             "cons-order",
                                 xenstore_gather_type_int,
                                 &consumer_ring_order,
                             "control-gref",
                                  xenstore_gather_type_alien_grant_ref,
                                  &chan->u.supplicant.control_gref,
                             "prod-evtchn",
                                  xenstore_gather_type_alien_evtchn_port,
                                  &chan->u.supplicant.prod_evtchn_port,
                             "cons-evtchn",
                                  xenstore_gather_type_alien_evtchn_port,
                                  &chan->u.supplicant.cons_evtchn_port,
                             NULL);
        if (!NT_SUCCESS(status))
            goto err;

        if (producer_ring_order > MAX_RING_PAGE_ORDER ||
            consumer_ring_order > MAX_RING_PAGE_ORDER) {
            status = STATUS_INVALID_PARAMETER;
            goto err;
        }

        for (x = 0; x < 1 << producer_ring_order; x++) {
            status = v2v_read_grantref(chan, xbt, x, TRUE);
            if (!NT_SUCCESS(status))
                goto err;
        }

        for (x = 0; x < 1 << consumer_ring_order; x++) {
            status = v2v_read_grantref(chan, xbt, x, FALSE);
            if (!NT_SUCCESS(status))
                goto err;
        }
        
        status = 
            v2v_xenops_grant_map((volatile void **)&chan->cons_sring,
                                 &chan->u.supplicant.prod_detail,
                                 chan->peer_domid,
                                 1 << producer_ring_order,
                                 chan->u.supplicant.prod_grefs,
                                 TRUE);
        if (!NT_SUCCESS(status))
            goto err;
        status = 
            v2v_xenops_grant_map((volatile void **)&chan->prod_sring,
                                 &chan->u.supplicant.cons_detail,
                                 chan->peer_domid,
                                 1 << consumer_ring_order,
                                 chan->u.supplicant.cons_grefs,
                                 FALSE);
        if (!NT_SUCCESS(status))
            goto err;
        status = 
            v2v_xenops_grant_map((volatile void **)&chan->control,
                                 &chan->u.supplicant.control_detail,
                                 chan->peer_domid,
                                 1,
                                 &chan->u.supplicant.control_gref,
                                 FALSE);
        if (!NT_SUCCESS(status))
            goto err;

        chan->receive_evtchn_port = 
            EvtchnConnectRemotePort(chan->peer_domid,
                                    chan->u.supplicant.prod_evtchn_port,
                                    (chan->is_sync ? v2v_dpc : async_values->receive_dpc),
                                    (chan->is_sync ? &chan->s.sync.receive_event : async_values->receive_ctx));
        if (is_null_EVTCHN_PORT(chan->receive_evtchn_port)) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto err;
        }

        chan->send_evtchn_port = 
            EvtchnConnectRemotePort(chan->peer_domid,
                                    chan->u.supplicant.cons_evtchn_port,
                                    (chan->is_sync ? v2v_dpc : async_values->send_dpc),
                                    (chan->is_sync ? &chan->s.sync.send_event : async_values->send_ctx));
        if (is_null_EVTCHN_PORT(chan->send_evtchn_port)) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto err;
        }

        status = v2v_change_local_state(chan, xbt, v2v_state_connected);
        if (!NT_SUCCESS(status))
            goto err;

        status = xenbus_transaction_end(xbt, 0);
        xbt_pending = FALSE;
        if (NT_SUCCESS(status))
            break;
        if (status != STATUS_RETRY)
            goto err;

        /* cleanup and try again */
        v2v_destroy_channel(chan, FALSE);      
    }

    /* Swap them round: *_ring_order is from the point of view of the
       temple, but we need the supplicant's viewpoint. */
    chan->nr_prod_ring_pages = 1 << consumer_ring_order;
    chan->nr_cons_ring_pages = 1 << producer_ring_order;

    v2v_nc2_attach_rings_supplicant(&chan->nc2_rings,
                                    chan->cons_sring,
                                    PAGE_SIZE << producer_ring_order,
                                    chan->prod_sring,
                                    PAGE_SIZE << consumer_ring_order,
                                    chan->control);

    *channel = chan;
 
    return STATUS_SUCCESS;

err:
    if (xbt_pending)
        xenbus_transaction_end(xbt, 1);
    v2v_destroy_channel(chan, FALSE);
    return status;
}
Esempio n. 16
0
static NTSTATUS
XenLowerConnectBackendInternal(
    PXEN_LOWER XenLower,
    SUSPEND_TOKEN Token)
{
    NTSTATUS status = STATUS_SUCCESS;
    XENBUS_STATE state;
    xenbus_transaction_t xbt;
    PCHAR fepath;

    if (is_null_EVTCHN_PORT(XenLower->EvtchnPort))
    {
        TraceError((__FUNCTION__ ": no event channel port, this routine must be called after event channel initialization\n"));
        return STATUS_UNSUCCESSFUL;
    }

    //---------------------------Backend Wait Ready-------------------------------//
    //
    // Wait for backend to get ready for initialization.
    //

    status = xenbus_change_state(XBT_NIL,
        XenLower->FrontendPath,
        "state",
        XENBUS_STATE_INITIALISING);
    if (!NT_SUCCESS(status))
    {
        TraceWarning((__FUNCTION__
            ": Failed to change front end state to XENBUS_STATE_INITIALISING(%d) status: 0x%x\n",
            XENBUS_STATE_INITIALISING, status));
        // Go on, best effort, chin up
    }

    TraceInfo((__FUNCTION__
        ": Front end state set to XENBUS_STATE_INITIALISING(%d)\n",
        XENBUS_STATE_INITIALISING));

    state = null_XENBUS_STATE();
    for ( ; ; )
    {
        // Turns out suspend tokens are not even used.
        state = XenbusWaitForBackendStateChange(XenLower->BackendPath,
            state, NULL, Token);

        if (same_XENBUS_STATE(state, XENBUS_STATE_INITWAIT))
        {
            break;
        }

        if (same_XENBUS_STATE(state, XENBUS_STATE_CLOSING) ||
            is_null_XENBUS_STATE(state))
        {
            TraceError((__FUNCTION__ ": backend '%s' went away before we could connect to it?\n",
                XenLower->BackendPath));

            status = STATUS_UNSUCCESSFUL;
            break;
        }
    }

    if (status != STATUS_SUCCESS)
    {
        return status;
    }

    TraceInfo((__FUNCTION__
        ": Back end state went to XENBUS_STATE_INITWAIT(%d)\n",
        XENBUS_STATE_INITWAIT));
    
    //----------------------------Backend Connect---------------------------------//    

    //
    // Communicate configuration to backend.
    //

    fepath = XenLower->FrontendPath;
    do {
        xenbus_transaction_start(&xbt);
        xenbus_write_grant_ref(xbt, fepath, "ring-ref", XenLower->SringGrantRef);
        xenbus_write_evtchn_port(xbt, fepath, "event-channel", XenLower->EvtchnPort);
        xenbus_change_state(xbt, fepath, "state", XENBUS_STATE_CONNECTED);
        status = xenbus_transaction_end(xbt, 0);
    } while (status == STATUS_RETRY);

    if (status != STATUS_SUCCESS)
    {
        TraceError((__FUNCTION__ ": failed to configure xenstore frontend values.\n"));
        return STATUS_UNSUCCESSFUL;
    }

    TraceInfo((__FUNCTION__
        ": Front end state set to XENBUS_STATE_CONNECTED(%d)\n",
        XENBUS_STATE_CONNECTED));

    //
    // Wait for backend to accept configuration and complete initialization.
    //

    state = null_XENBUS_STATE();
    for ( ; ; )
    {
        state = XenbusWaitForBackendStateChange(XenLower->BackendPath,
            state, NULL, Token);

        if (is_null_XENBUS_STATE(state) ||
            same_XENBUS_STATE(state, XENBUS_STATE_CLOSING) ||
            same_XENBUS_STATE(state, XENBUS_STATE_CLOSED))
        {

            TraceError((__FUNCTION__ ": Failed to connected '%s' <-> '%s' backend state: %d\n",
                XenLower->FrontendPath,
                XenLower->BackendPath,
                state));

            status = STATUS_UNSUCCESSFUL;
            break;
        }

        if (same_XENBUS_STATE(state, XENBUS_STATE_CONNECTED))
        {
            TraceNotice((__FUNCTION__ ": Connected '%s' <-> '%s' \n",
                XenLower->FrontendPath,
                XenLower->BackendPath));
            TraceInfo((__FUNCTION__
                ": Back end final state went to XENBUS_STATE_CONNECTED(%d)\n",
                XENBUS_STATE_CONNECTED));
            break;
        }
    }

    return status;
}
Esempio n. 17
0
NTSTATUS
v2v_listen(const char *xenbus_prefix, struct v2v_channel **channel,
           unsigned prod_ring_page_order, unsigned cons_ring_page_order,
           struct v2v_async *async_values)
{
    NTSTATUS status = STATUS_SUCCESS;
    unsigned prod_ring_size = PAGE_SIZE << prod_ring_page_order;
    unsigned cons_ring_size = PAGE_SIZE << cons_ring_page_order;
    struct v2v_channel *chan;
    xenbus_transaction_t xbt = {0};
    BOOLEAN xbt_pending = FALSE;
    PHYSICAL_ADDRESS pa;
    unsigned x;
    unsigned xen_receive_port, xen_send_port;
    uint32_t xen_gref;

    XM_ASSERT(channel != NULL);
    XM_ASSERT(xenbus_prefix != NULL);

    if (prod_ring_page_order > MAX_RING_PAGE_ORDER ||
        cons_ring_page_order > MAX_RING_PAGE_ORDER)
        return STATUS_INVALID_PARAMETER;

    if (async_values && 
       (!async_values->receive_dpc || !async_values->send_dpc))
        return STATUS_INVALID_PARAMETER;

    *channel = NULL;

    if (!xenbus_await_initialisation())
        return STATUS_NO_SUCH_DEVICE;

    chan = v2v_make_channel(xenbus_prefix, async_values);
    if (!chan)
        return STATUS_NO_MEMORY;

    chan->is_temple = TRUE;

    chan->prod_sring = ExAllocatePoolWithTag(NonPagedPool, prod_ring_size, V2V_TAG);
    chan->cons_sring = ExAllocatePoolWithTag(NonPagedPool, cons_ring_size, V2V_TAG);
    chan->control = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, V2V_TAG);
    if (!chan->prod_sring || !chan->cons_sring || !chan->control)
        goto err_nomem;

    RtlZeroMemory(chan->prod_sring, prod_ring_size);
    RtlZeroMemory((void *)chan->cons_sring, cons_ring_size);
    RtlZeroMemory(chan->control, PAGE_SIZE);

    chan->nr_prod_ring_pages = 1 << prod_ring_page_order;
    chan->nr_cons_ring_pages = 1 << cons_ring_page_order;

    /* pre-allocate the granf refs we are going to need below in a grant cache */
    chan->u.temple.grant_cache =
        GnttabAllocCache(chan->nr_prod_ring_pages + chan->nr_cons_ring_pages + 1);
    if (!chan->u.temple.grant_cache)
        goto err_nomem;

    v2v_nc2_attach_rings_temple(&chan->nc2_rings,
                                chan->cons_sring,
                                cons_ring_size,
                                chan->prod_sring,
                                prod_ring_size,
                                chan->control);

    for (;;) {
        xenbus_transaction_start(&xbt);        
        xbt_pending = TRUE;
        
        status = v2v_connect_channel_xenbus(chan, xbt);
        if (!NT_SUCCESS(status))
            goto err;        

        for (x = 0; x < 1u << prod_ring_page_order; x++) {
            pa = MmGetPhysicalAddress((void *)((ULONG_PTR)chan->prod_sring + x * PAGE_SIZE));
            chan->u.temple.prod_grefs[x] =
                GnttabGrantForeignAccessCache(chan->peer_domid,
                                              PHYS_TO_PFN(pa),
                                              GRANT_MODE_RO,
                                              chan->u.temple.grant_cache);
            XM_ASSERT(!is_null_GRANT_REF(chan->u.temple.prod_grefs[x]));

            status = v2v_write_grantref(chan, xbt, x, TRUE);
            if (!NT_SUCCESS(status))          
                goto err;
        }

        for (x = 0; x < 1u << cons_ring_page_order; x++) {
            pa = MmGetPhysicalAddress((void *)((ULONG_PTR)chan->cons_sring + x * PAGE_SIZE));
            chan->u.temple.cons_grefs[x] =
                GnttabGrantForeignAccessCache(chan->peer_domid,
                                              PHYS_TO_PFN(pa),
                                              GRANT_MODE_RW,
                                              chan->u.temple.grant_cache);
            XM_ASSERT(!is_null_GRANT_REF(chan->u.temple.cons_grefs[x]));

            status = v2v_write_grantref(chan, xbt, x, FALSE);
            if (!NT_SUCCESS(status))
                goto err;
        }

        pa = MmGetPhysicalAddress((void *)((ULONG_PTR)chan->control));
        chan->u.temple.control_gref =
            GnttabGrantForeignAccessCache(chan->peer_domid,
                                          PHYS_TO_PFN(pa),
                                          GRANT_MODE_RW,
                                          chan->u.temple.grant_cache);
        XM_ASSERT(!is_null_GRANT_REF(chan->u.temple.control_gref));

        chan->receive_evtchn_port = 
            EvtchnAllocUnboundDpc(chan->peer_domid,
                                  (chan->is_sync ? v2v_dpc : async_values->receive_dpc),
                                  (chan->is_sync ? &chan->s.sync.receive_event : async_values->receive_ctx));
        if (is_null_EVTCHN_PORT(chan->receive_evtchn_port)) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto err;
        }
        xen_receive_port = xen_EVTCHN_PORT(chan->receive_evtchn_port);

        chan->send_evtchn_port = 
            EvtchnAllocUnboundDpc(chan->peer_domid,
                                  (chan->is_sync ? v2v_dpc : async_values->send_dpc),
                                  (chan->is_sync ? &chan->s.sync.send_event : async_values->send_ctx));
        if (is_null_EVTCHN_PORT(chan->send_evtchn_port)) {
            status = STATUS_INSUFFICIENT_RESOURCES;
            goto err;
        }
        xen_send_port = xen_EVTCHN_PORT(chan->send_evtchn_port);

        xen_gref = xen_GRANT_REF(chan->u.temple.control_gref);
        status = 
            v2v_xenstore_scatter(xbt, chan->local_prefix,
                                 "prod-order", xenstore_scatter_type_int,
                                     prod_ring_page_order,
                                 "cons-order", xenstore_scatter_type_int,
                                     cons_ring_page_order,
                                 "control-gref", xenstore_scatter_type_grant_ref,
                                     xen_gref,
                                 "prod-evtchn",xenstore_scatter_type_evtchn_port,
                                     xen_send_port,
                                 "cons-evtchn",xenstore_scatter_type_evtchn_port,
                                     xen_receive_port,
                                 NULL);
        if (!NT_SUCCESS(status))
            goto err;

        status = v2v_change_local_state(chan, xbt, v2v_state_listening);
        if (!NT_SUCCESS(status))
            goto err;

        status = xenbus_transaction_end(xbt, 0);
        xbt_pending = FALSE;
        if (NT_SUCCESS(status))
            break;
        if (status != STATUS_RETRY)
            goto err;

        /* cleanup for retry */
        for (x = 0; x < 1u << prod_ring_page_order; x++) {
            GnttabEndForeignAccessCache(chan->u.temple.prod_grefs[x],
                                        chan->u.temple.grant_cache);
        }
        RtlZeroMemory(chan->u.temple.prod_grefs, sizeof(chan->u.temple.prod_grefs));

        for (x = 0; x < 1u << cons_ring_page_order; x++) {
            GnttabEndForeignAccessCache(chan->u.temple.cons_grefs[x],
                                        chan->u.temple.grant_cache);
        }
        RtlZeroMemory(chan->u.temple.cons_grefs, sizeof(chan->u.temple.cons_grefs));

        GnttabEndForeignAccessCache(chan->u.temple.control_gref,
                                    chan->u.temple.grant_cache);
        chan->u.temple.control_gref = null_GRANT_REF();

        EvtchnClose(chan->receive_evtchn_port);
        chan->receive_evtchn_port = null_EVTCHN_PORT();
        EvtchnClose(chan->send_evtchn_port);
        chan->send_evtchn_port = null_EVTCHN_PORT();

        xenbus_unregister_watch(chan->remote_state_watch);
        chan->remote_state_watch = NULL;
        ExFreePoolWithTag(chan->remote_prefix, V2V_TAG);
        chan->remote_prefix = NULL;
    }

    *channel = chan;

    return STATUS_SUCCESS;

err_nomem:
    status = STATUS_NO_MEMORY;
err:
    if (xbt_pending)
        xenbus_transaction_end(xbt, 1);
    /* since the channel has never been connected here, it is safe 
       to free any temple resources that may have been allocated in 
       this routine */
    v2v_destroy_channel(chan, TRUE);
    return status;
}
Esempio n. 18
0
static NTSTATUS
v2v_disconnect_temple(const struct v2v_channel *_channel)
{
    NTSTATUS status = STATUS_SUCCESS;
    xenbus_transaction_t xbt = {0};
    struct v2v_channel *channel = (struct v2v_channel *)_channel;
    enum v2v_endpoint_state remote_state;
    BOOLEAN failed, any_failed = FALSE;
    unsigned x;

    status = v2v_change_local_state(channel, XBT_NIL, v2v_state_disconnecting);
    if (!NT_SUCCESS(status))
        return status;
    channel->u.temple.accepted = FALSE;

    /* Get the other end to disconnect */
    for (;;) {
        xenbus_transaction_start(&xbt);
        status = v2v_get_remote_state_internal(xbt, channel, &remote_state);
        switch (remote_state) {
        case v2v_state_unknown:            
            if (status == STATUS_OBJECT_NAME_NOT_FOUND)
                break;
            xenbus_transaction_end(xbt, 1);
            return status;

            /* The first two shouldn't really happen, but sometimes
               can if we've managed to screw (e.g.  if two processes
               try to use the same endpoint).  Try to recover. */
        case v2v_state_unready:
        case v2v_state_listening:
        case v2v_state_disconnecting:

        case v2v_state_disconnected:
        case v2v_state_crashed:
            break;
        case v2v_state_connected:
            xenbus_transaction_end(xbt, 1);
            KeWaitForSingleObject(&channel->control_event, Executive,
                                  KernelMode, FALSE, NULL);
            continue;
        }
        status = v2v_change_local_state(channel, xbt, v2v_state_disconnected);
        if (!NT_SUCCESS(status)) {            
            xenbus_transaction_end(xbt, 1);
            return status;
        }

        status = xenbus_transaction_end(xbt, 0);
        if (NT_SUCCESS(status))
            break; /* drop out of loop and do rest */
        if (status == STATUS_RETRY)
            continue; /* try again */
        return status; /* else return the error */
    }

    XM_ASSERT(channel->u.temple.grant_cache != NULL);

    failed = FALSE;
    for (x = 0; x < channel->nr_prod_ring_pages; x++) {
        if (!is_null_GRANT_REF(channel->u.temple.prod_grefs[x])) {
            status = GnttabEndForeignAccessCache(channel->u.temple.prod_grefs[x],
                                                 channel->u.temple.grant_cache);
            if (NT_SUCCESS(status))
                channel->u.temple.prod_grefs[x] = null_GRANT_REF();
            else
                failed = any_failed = TRUE;
        }
    }
    if (!failed) {
        ExFreePoolWithTag(channel->prod_sring, V2V_TAG);
        channel->prod_sring = NULL;
    }

    failed = FALSE;
    for (x = 0; x < channel->nr_cons_ring_pages; x++) {
        if (!is_null_GRANT_REF(channel->u.temple.cons_grefs[x])) {
            status = GnttabEndForeignAccessCache(channel->u.temple.cons_grefs[x],
                                                 channel->u.temple.grant_cache);
            if (NT_SUCCESS(status))
                channel->u.temple.cons_grefs[x] = null_GRANT_REF();
            else
                failed = any_failed = TRUE;
        }
    }
    if (!failed) {
		ExFreePoolWithTag((void *)channel->cons_sring, V2V_TAG);
        channel->cons_sring = NULL;
    }

    if (!is_null_GRANT_REF(channel->u.temple.control_gref)) {
        status = GnttabEndForeignAccessCache(channel->u.temple.control_gref,
                                             channel->u.temple.grant_cache);
        if (NT_SUCCESS(status)) {
            channel->u.temple.control_gref = null_GRANT_REF();
			ExFreePoolWithTag(channel->control, V2V_TAG);
            channel->control = NULL;
        }
        else
            any_failed = TRUE;
    }

    if (!any_failed)
        GnttabFreeCache(channel->u.temple.grant_cache);

    if (!is_null_EVTCHN_PORT(channel->receive_evtchn_port)) {
        EvtchnClose(channel->receive_evtchn_port);
        channel->receive_evtchn_port = null_EVTCHN_PORT();
    }
    if (!is_null_EVTCHN_PORT(channel->send_evtchn_port)) {
        EvtchnClose(channel->send_evtchn_port);
        channel->send_evtchn_port = null_EVTCHN_PORT();
    }

    /* We either freed the rings here or they could not be freed. Prevent
       v2v_destroy_channel() from trying to free grants/rings with 
       outstanding grant refs */
    v2v_destroy_channel(channel, FALSE);
    
    return STATUS_SUCCESS;
}