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); }
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; }
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; }
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); }
static VOID V4vVirqNotifyIsr(VOID *ctx) { XENV4V_EXTENSION *pde = V4vGetDeviceExtension((DEVICE_OBJECT*)ctx); // Just drop out of ISR context KeInsertQueueDpc(&pde->virqDpc, NULL, NULL); }
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")); }
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; }
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; }
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; }