Ejemplo n.º 1
0
static VOID
V4vConnectTimerDpc(KDPC *dpc, VOID *dctx, PVOID sarg1, PVOID sarg2)
{
    XENV4V_EXTENSION  *pde = V4vGetDeviceExtension((DEVICE_OBJECT*)dctx);
    XENV4V_CONTEXT   **ctxList;
    ULONG              count = 0, i;

    UNREFERENCED_PARAMETER(dpc);
    UNREFERENCED_PARAMETER(sarg1);
    UNREFERENCED_PARAMETER(sarg2);

    // The periodic timer is used to driver the connector SYN/ACK state machine.
    // Ultimately it simply drives the receive logic just as the the notify
    // DPC does. It should only be active when there are contexts in the 
    // CONNECTING state present.

    // Get a list of active contexts and their rings
    ctxList = V4vGetAllContexts(pde, &count);

    // Loop over the contexts and process read IO for each.
    for (i = 0; ((ctxList != NULL)&&(i < count)); i++) {
        V4vProcessContextReads(pde, ctxList[i]);
    }

    // Return the context list and drop the ref count
    V4vPutAllContexts(pde, ctxList, count);
}
Ejemplo n.º 2
0
static NTSTATUS NTAPI
V4vDispatchWmi(PDEVICE_OBJECT fdo, PIRP irp)
{
    NTSTATUS          status;
    PXENV4V_EXTENSION pde = V4vGetDeviceExtension(fdo);

    TraceVerbose(("====> '%s'.\n", __FUNCTION__));

    // We don't support WMI, so just pass it on down the stack

    status = IoAcquireRemoveLock(&pde->removeLock, irp);
    if (!NT_SUCCESS(status)) {
        TraceError(("failed to acquire IO lock - error: 0x%x\n", status));        
        return V4vSimpleCompleteIrp(irp, status);
    }

    IoSkipCurrentIrpStackLocation(irp);
    status = IoCallDriver(pde->ldo, irp);

    IoReleaseRemoveLock(&pde->removeLock, irp);

    TraceVerbose(("<==== '%s'.\n", __FUNCTION__));
 
    return status;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
static VOID
V4vVirqNotifyDpc(KDPC *dpc, VOID *dctx, PVOID sarg1, PVOID sarg2)
{
    XENV4V_EXTENSION  *pde = V4vGetDeviceExtension((DEVICE_OBJECT*)dctx);
    XENV4V_CONTEXT   **ctxList;
    ULONG              count = 0, i;
    KLOCK_QUEUE_HANDLE lqh;

    UNREFERENCED_PARAMETER(dpc);
    UNREFERENCED_PARAMETER(sarg1);
    UNREFERENCED_PARAMETER(sarg2);

    // In MP guests when not using VIRQs, have to lock the DPC processing
    KeAcquireInStackQueuedSpinLockAtDpcLevel(&pde->dpcLock, &lqh);

    // Get a list of active contexts and their rings
    ctxList = V4vGetAllContexts(pde, &count);

    // Loop over the contexts and process read IO for each.
    for (i = 0; ((ctxList != NULL)&&(i < count)); i++) {
        V4vProcessContextReads(pde, ctxList[i]);        
    }

    // Return the context list and drop the ref count
    V4vPutAllContexts(pde, ctxList, count);

    // Now process the notify and satisfy writes that are queued
    V4vProcessNotify(pde);

    KeReleaseInStackQueuedSpinLockFromDpcLevel(&lqh);
}
Ejemplo n.º 5
0
static VOID
V4vVirqNotifyIsr(VOID *ctx)
{
    XENV4V_EXTENSION *pde = V4vGetDeviceExtension((DEVICE_OBJECT*)ctx);

    // Just drop out of ISR context
    KeInsertQueueDpc(&pde->virqDpc, NULL, NULL);
}
Ejemplo n.º 6
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"));
}
Ejemplo n.º 7
0
NTSTATUS NTAPI
V4vDispatchDeviceControl(PDEVICE_OBJECT fdo, PIRP irp)
{
    NTSTATUS            status = STATUS_SUCCESS;
    PIO_STACK_LOCATION  isl;
    ULONG               ioControlCode;
    PVOID               ioBuffer;
    ULONG               ioInLen;
    ULONG               ioOutLen;
    XENV4V_EXTENSION   *pde = V4vGetDeviceExtension(fdo);
    XENV4V_CONTEXT     *ctx;
    LONG                ds;

    TraceVerbose(("====> '%s'.\n", __FUNCTION__));

    isl           = IoGetCurrentIrpStackLocation(irp);
    ioControlCode = isl->Parameters.DeviceIoControl.IoControlCode;
    ioBuffer      = irp->AssociatedIrp.SystemBuffer;
    ioInLen       = isl->Parameters.DeviceIoControl.InputBufferLength;
    ioOutLen      = isl->Parameters.DeviceIoControl.OutputBufferLength;
    ctx           = (XENV4V_CONTEXT*)isl->FileObject->FsContext;

    TraceVerbose((" =IOCTL= 0x%x\n", ioControlCode));

    irp->IoStatus.Information = 0;

    ds = InterlockedExchangeAdd(&pde->state, 0);
    if (ds & XENV4V_DEV_STOPPED) {
        TraceVerbose(("aborting IOCTL IRP, device is in the stopped state.\n"));
        irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
        TraceVerbose(("<==== '%s'.\n", __FUNCTION__));
        return STATUS_INVALID_DEVICE_STATE;
    }

    switch (ioControlCode) {
#if defined(_WIN64)
    case V4V_IOCTL_INITIALIZE_32:
    {
        V4V_INIT_VALUES_32 *invs32 = (V4V_INIT_VALUES_32*)ioBuffer;
        if (ioInLen == sizeof(V4V_INIT_VALUES_32)) {
            V4V_INIT_VALUES init;
            init.rxEvent = invs32->rxEvent;
            init.ringLength = invs32->ringLength;
            status = V4vCtrlInitializeFile(ctx, &init, irp);
        }
        else {
            TraceError(("invalid initialization values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
#endif
    case V4V_IOCTL_INITIALIZE:
    {
        V4V_INIT_VALUES *invs = (V4V_INIT_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_INIT_VALUES)) {
            status = V4vCtrlInitializeFile(ctx, invs, irp);
        }
        else {
            TraceError(("invalid initialization values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
    case V4V_IOCTL_BIND:
    {
        V4V_BIND_VALUES *bvs = (V4V_BIND_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_BIND_VALUES)) {
            status = V4vCtrlBind(pde, ctx, bvs);
        }
        else {
            TraceError(("invalid bind values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
    case V4V_IOCTL_LISTEN:
    {
        V4V_LISTEN_VALUES *lvs = (V4V_LISTEN_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_LISTEN_VALUES)) {
            status = V4vCtrlListen(ctx, lvs);
        }
        else {
            TraceError(("invalid listen values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
#if defined(_WIN64)
    case V4V_IOCTL_ACCEPT_32: // Fall through
#endif
    case V4V_IOCTL_ACCEPT:
    {
        status = V4vCtrlAccept(pde, ctx, ioControlCode, ioBuffer, ioInLen, irp);
        break;
    }
    case V4V_IOCTL_CONNECT:
    {
        V4V_CONNECT_VALUES *cvs = (V4V_CONNECT_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_CONNECT_VALUES)) {
            status = V4vCtrlConnect(pde, ctx, cvs, irp);
        }
        else {
            TraceError(("invalid connect values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }
      
        break;
    }
    case V4V_IOCTL_WAIT:
    {
        V4V_WAIT_VALUES *wvs = (V4V_WAIT_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_WAIT_VALUES)) {
            status = V4vCtrlConnectWait(pde, ctx, wvs, irp);
        }
        else {
            TraceError(("invalid connect wait values.\n"));
            status = STATUS_INVALID_PARAMETER;
        }

        break;
    }
    case V4V_IOCTL_DISCONNECT:
    {
        status = V4vCtrlDisconnect(pde, ctx);      
        break;
    }
    case V4V_IOCTL_GETINFO:
    {
        V4V_GETINFO_VALUES *gi = (V4V_GETINFO_VALUES*)ioBuffer;
        if (ioInLen == sizeof(V4V_GETINFO_VALUES)) {
            status = V4vCtrlGetInfo(ctx, gi);
        }
        else {
            TraceError(("invalid get info values.\n"));
	        status = STATUS_INVALID_PARAMETER;
        }

        if (NT_SUCCESS(status)) {
            irp->IoStatus.Information = sizeof(V4V_GETINFO_VALUES);
        }

        break;
    }
    case V4V_IOCTL_DUMPRING:
    {
        status = V4vCtrlDumpRing(ctx);
        break;
    }
    default:
        status = STATUS_INVALID_PARAMETER;		
    }

    if (status != STATUS_PENDING) {
        irp->IoStatus.Status = status;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
    }

    TraceVerbose(("<==== '%s'.\n", __FUNCTION__));

    return status;
}
Ejemplo n.º 8
0
static NTSTATUS NTAPI
V4vDispatchPower(PDEVICE_OBJECT fdo, PIRP irp)
{
    NTSTATUS           status;
    PXENV4V_EXTENSION  pde = V4vGetDeviceExtension(fdo);
    PIO_STACK_LOCATION isl = IoGetCurrentIrpStackLocation(irp);

    TraceVerbose(("====> '%s'.\n", __FUNCTION__));

    switch (isl->MinorFunction) {
    case IRP_MN_SET_POWER:
        if (isl->Parameters.Power.Type == SystemPowerState) {
            TraceNotice(("SET system power: %d %d\n",
                          isl->Parameters.Power.State.SystemState,
                          isl->Parameters.Power.ShutdownType));

            // If we are transitioning from the working (S0) power state to a lower state,
            // disconnect the VIRQ. If we are resuming to the working power state, re-connect.           
            if (isl->Parameters.Power.State.SystemState == PowerSystemWorking) {
                // When resuming from hibernation w/ multi-vCPUs, the pv drivers
                // may be initialized in parallel causing problems with xenbus being
                // initialized before we try to bind our VIRQ. Kick the job off to a 
                // work item and wait for initialization there.
                if (pde->lastPoState == PowerSystemHibernate) {
                    V4vStartDehibernateWorkItem(fdo);
                }
                else {
                    (VOID)V4vInitializeEventChannel(fdo);
                }
            }
            else if (isl->Parameters.Power.State.SystemState >= PowerSystemSleeping1) {
                V4vUninitializeEventChannel(fdo);               
            }

            // If the last state was S4, flush all connections
            if (pde->lastPoState == PowerSystemHibernate) {
                V4vDisconnectAllStreams(pde);
            }

            // Reset the last state to what we just saw
            pde->lastPoState = isl->Parameters.Power.State.SystemState;
        }
        else if (isl->Parameters.Power.Type == DevicePowerState) {
            TraceNotice(("SET device power: %d %d\n",
                         isl->Parameters.Power.State.SystemState,
                         isl->Parameters.Power.ShutdownType));
        }
        break;
    case IRP_MN_QUERY_POWER:
        if (isl->Parameters.Power.Type == SystemPowerState) {
            TraceNotice(("QUERY system power: %d %d\n",
                          isl->Parameters.Power.State.SystemState,
                          isl->Parameters.Power.ShutdownType));
        }
        else if (isl->Parameters.Power.Type == DevicePowerState) {
            TraceNotice(("QUERY device power: %d %d\n",
                         isl->Parameters.Power.State.SystemState,
                         isl->Parameters.Power.ShutdownType));
        }
        break;
    };    

    status = IoAcquireRemoveLock(&pde->removeLock, irp);
    if (!NT_SUCCESS(status)) {
        TraceError(("failed to acquire IO lock - error: 0x%x\n", status));
        PoStartNextPowerIrp(irp); // for xp and 2k3
        return V4vSimpleCompleteIrp(irp, status);
    }

    PoStartNextPowerIrp(irp); // for xp and 2k3
    IoSkipCurrentIrpStackLocation(irp);
    status = PoCallDriver(pde->ldo, irp);

    IoReleaseRemoveLock(&pde->removeLock, irp);

    TraceVerbose(("<==== '%s'.\n", __FUNCTION__));

    return status;
}
Ejemplo n.º 9
0
static NTSTATUS NTAPI
V4vDispatchPnP(PDEVICE_OBJECT fdo, PIRP irp)
{
    NTSTATUS           status = STATUS_SUCCESS;
    PIO_STACK_LOCATION isl = IoGetCurrentIrpStackLocation(irp);
    PXENV4V_EXTENSION  pde = V4vGetDeviceExtension(fdo);
    KEVENT             kev;

    TraceVerbose(("====> '%s'.\n", __FUNCTION__));

    TraceVerbose((" =PnP= 0x%x\n", isl->MinorFunction));

    status = IoAcquireRemoveLock(&pde->removeLock, irp);
    if (!NT_SUCCESS(status)) {
        TraceError(("failed to acquire IO lock - error: 0x%x\n", status));
        return V4vSimpleCompleteIrp(irp, status);
    }

    switch (isl->MinorFunction) {
    case IRP_MN_START_DEVICE:
        KeInitializeEvent(&kev, NotificationEvent, FALSE);
        // Send the start down and wait for it to complete
        IoCopyCurrentIrpStackLocationToNext(irp);
        IoSetCompletionRoutine(irp, V4vStartDeviceIoCompletion, &kev, TRUE, TRUE, TRUE);
        status = IoCallDriver(pde->ldo, irp);
        if (status == STATUS_PENDING) {
            // Wait for everything underneath us to complete
            TraceVerbose(("Device start waiting for lower device.\n"));
            KeWaitForSingleObject(&kev, Executive, KernelMode, FALSE, NULL);
            TraceVerbose(("Device start wait finished.\n"));
        }

        status = irp->IoStatus.Status;
        if (!NT_SUCCESS(status)) {
            TraceError(("Failed to start lower drivers: %x.\n", status));
            IoCompleteRequest(irp, IO_NO_INCREMENT);
            break;
        }

        status = STATUS_SUCCESS;

        // Connect our interrupt (ec).
        status = V4vInitializeEventChannel(fdo);
        if (NT_SUCCESS(status)) {
            InterlockedExchange(&pde->state, XENV4V_DEV_STARTED);
        }
        else {
            TraceError(("failed to initialize event channel - error: 0x%x\n", status));
        }

        irp->IoStatus.Status = status;
        IoCompleteRequest(irp, IO_NO_INCREMENT);
        break;
    case IRP_MN_STOP_DEVICE:
        // Stop our device's IO processing
        V4vStopDevice(fdo, pde);

        // Pass it down
        irp->IoStatus.Status = STATUS_SUCCESS;
        IoSkipCurrentIrpStackLocation(irp);
        status = IoCallDriver(pde->ldo, irp);
        break;        
    case IRP_MN_REMOVE_DEVICE:
        // Stop our device's IO processing
        V4vStopDevice(fdo, pde);

        // Cleanup anything here that locks for IO
        IoReleaseRemoveLockAndWait(&pde->removeLock, irp);

        // Pass it down first
        IoSkipCurrentIrpStackLocation(irp);
        status = IoCallDriver(pde->ldo, irp);

        // Then detach and cleanup our device
        xenbus_change_state(XBT_NIL, pde->frontendPath, "state", XENBUS_STATE_CLOSED);
        IoDetachDevice(pde->ldo);
        ExDeleteNPagedLookasideList(&pde->destLookasideList);
        XmFreeMemory(pde->frontendPath);
        IoDeleteSymbolicLink(&pde->symbolicLink);
        IoDeleteDevice(fdo);
        InterlockedAnd(&g_deviceCreated, 0);
        return status;
    default:
        // Pass it down
        TraceVerbose(("IRP_MJ_PNP MinorFunction %d passed down\n", isl->MinorFunction));
        IoSkipCurrentIrpStackLocation(irp);
        status = IoCallDriver(pde->ldo, irp);
    };

    // Everybody but REMOVE
    IoReleaseRemoveLock(&pde->removeLock, irp); 

    TraceVerbose(("<==== '%s'.\n", __FUNCTION__));

    return status;
}