VOID FxPkgIo::ResetStateForRestart( VOID ) /*++ Routine Description: This is called on a device which has been restarted from the removed state. It will reset purged queues so that they can accept new requests when ResumeProcessingForPower is called afterwards. Arguments: None Return Value: None --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Restart queues from purged state for WDFDEVICE 0x%p due to " "device restart", m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOn); Unlock(irql); for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->ResetStateForRestart(); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } Lock(&irql); m_PowerStateOn = TRUE; m_QueuesAreShuttingDown = FALSE; Unlock(irql); return; }
VOID PushUnload( DRIVER_OBJECT* DriverObject ) { UNICODE_STRING DeviceLinkU; NTSTATUS ntStatus; PMAPINFO pMapInfo; PSINGLE_LIST_ENTRY pLink; DbgPrint("[Push] => (PushUnload)"); RdUnload(DriverObject); //free resources pLink=PopEntryList(&lstMapInfo); while(pLink) { pMapInfo=CONTAINING_RECORD(pLink, MAPINFO, link); MmUnmapLockedPages(pMapInfo->pvu, pMapInfo->pMdl); IoFreeMdl(pMapInfo->pMdl); MmUnmapIoSpace(pMapInfo->pvk, pMapInfo->memSize); ExFreePool(pMapInfo); pLink=PopEntryList(&lstMapInfo); } // // By default the I/O device is configured incorrectly or the // configuration parameters to the driver are incorrect. // ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR; // // restore the call back routine, thus givinig chance to the // user mode application to unload dynamically the driver // ntStatus = PsSetCreateProcessNotifyRoutine(ProcessCallback, TRUE); IoDeleteDevice(DriverObject->DeviceObject); RtlInitUnicodeString(&DeviceLinkU, PUSH_SYMLINK_NAME); ntStatus=IoDeleteSymbolicLink(&DeviceLinkU); if (NT_SUCCESS(ntStatus)) { IoDeleteDevice(DriverObject->DeviceObject); } else { DbgPrint("Error: IoDeleteSymbolicLink failed"); } DbgPrint("[Push] <= (PushUnload)"); }
NTSTATUS VIOSerialPortEvtDeviceD0Exit( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE TargetState ) { PVIOSERIAL_PORT Port = RawPdoSerialPortGetData(Device)->port; PPORT_BUFFER buf; PSINGLE_LIST_ENTRY iter; UNREFERENCED_PARAMETER(TargetState); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__); WdfIoQueuePurge(Port->ReadQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); WdfIoQueuePurge(Port->WriteQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); WdfIoQueuePurge(Port->IoctlQueue, WDF_NO_EVENT_CALLBACK, WDF_NO_CONTEXT); VIOSerialDisableInterruptQueue(GetInQueue(Port)); WdfSpinLockAcquire(Port->InBufLock); VIOSerialDiscardPortDataLocked(Port); Port->InBuf = NULL; WdfSpinLockRelease(Port->InBufLock); WdfSpinLockAcquire(Port->OutVqLock); VIOSerialReclaimConsumedBuffers(Port); WdfSpinLockRelease(Port->OutVqLock); while (buf = (PPORT_BUFFER)VirtIODeviceDetachUnusedBuf(GetInQueue(Port))) { VIOSerialFreeBuffer(buf); } iter = PopEntryList(&Port->WriteBuffersList); while (iter != NULL) { PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter, WRITE_BUFFER_ENTRY, ListEntry); ExFreePoolWithTag(entry->Buffer, VIOSERIAL_DRIVER_MEMORY_TAG); ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG); iter = PopEntryList(&Port->WriteBuffersList); }; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__); return STATUS_SUCCESS; }
PAPCCONTEXT DOVERLAPPEDSTRUCTMGR::AllocateApcContext() /*++ Routine Description: Allocates an APC context structure from the pool of available structures. Arguments: None Return Value: A pointer the a APC context struct on success else NULL. --*/ { PAPCCONTEXT ReturnValue; EnterCriticalSection(&m_context_free_list_lock); ReturnValue = (PAPCCONTEXT)PopEntryList(&m_context_free_list); if (ReturnValue){ ZeroMemory( ReturnValue, sizeof(APCCONTEXT)); } //if LeaveCriticalSection(&m_context_free_list_lock); return(ReturnValue); }
PSINGLE_LIST_ENTRY FASTCALL ExfInterlockedPopEntryList( IN OUT PSINGLE_LIST_ENTRY ListHead, IN OUT PKSPIN_LOCK Lock) { BOOLEAN Enable; PSINGLE_LIST_ENTRY ListEntry; /* Disable interrupts and acquire the spinlock */ Enable = _ExiDisableInteruptsAndAcquireSpinlock(Lock); /* Pop the first entry from the list */ ListEntry = PopEntryList(ListHead); #if DBG if (ListEntry) ListEntry->Next = (PSINGLE_LIST_ENTRY)0xBADDD0FF; #endif /* Release the spinlock and restore interrupts */ _ExiReleaseSpinLockAndRestoreInterupts(Lock, Enable); /* return the entry */ return ListEntry; }
PVOID ExAllocateFromPagedLookasideList( IN PPAGED_LOOKASIDE_LIST Lookaside ) /*++ Routine Description: This function removes (pops) the first entry from the specified paged lookaside list. Arguments: Lookaside - Supplies a pointer to a paged lookaside list structure. Return Value: If an entry is removed from the specified lookaside list, then the address of the entry is returned as the function value. Otherwise, NULL is returned. --*/ { PVOID Entry; Lookaside->L.TotalAllocates += 1; if (Isx86FeaturePresent(KF_CMPXCHG8B)) { if ((Entry = ExInterlockedPopEntrySList(&Lookaside->L.ListHead, NULL)) == NULL) { Lookaside->L.AllocateMisses += 1; Entry = (Lookaside->L.Allocate)(Lookaside->L.Type, Lookaside->L.Size, Lookaside->L.Tag); } return Entry; } ExAcquireFastMutex(&Lookaside->Lock); Entry = PopEntryList(&Lookaside->L.ListHead.Next); if (Entry == NULL) { ExReleaseFastMutex(&Lookaside->Lock); Lookaside->L.AllocateMisses += 1; Entry = (Lookaside->L.Allocate)(Lookaside->L.Type, Lookaside->L.Size, Lookaside->L.Tag); } else { Lookaside->L.ListHead.Depth -= 1; ExReleaseFastMutex(&Lookaside->Lock); } return Entry; }
NTSTATUS VIOSerialPortEvtDeviceD0Exit( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE TargetState ) { PVIOSERIAL_PORT Port = RawPdoSerialPortGetData(Device)->port; PPORT_BUFFER buf; PSINGLE_LIST_ENTRY iter; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s TargetState: %d\n", __FUNCTION__, TargetState); Port->Removed = TRUE; VIOSerialDisableInterruptQueue(GetInQueue(Port)); WdfSpinLockAcquire(Port->InBufLock); VIOSerialDiscardPortDataLocked(Port); Port->InBuf = NULL; WdfSpinLockRelease(Port->InBufLock); VIOSerialReclaimConsumedBuffers(Port); while (buf = (PPORT_BUFFER)virtqueue_detach_unused_buf(GetInQueue(Port))) { VIOSerialFreeBuffer(buf); } iter = PopEntryList(&Port->WriteBuffersList); while (iter != NULL) { PWRITE_BUFFER_ENTRY entry = CONTAINING_RECORD(iter, WRITE_BUFFER_ENTRY, ListEntry); ExFreePoolWithTag(entry->Buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfObjectDelete(entry->EntryHandle); iter = PopEntryList(&Port->WriteBuffersList); }; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__); return STATUS_SUCCESS; }
void PCIFreeBars(PVIRTIO_WDF_DRIVER pWdfDriver) { PSINGLE_LIST_ENTRY iter; /* unmap IO space and free our BAR descriptors */ while (iter = PopEntryList(&pWdfDriver->PCIBars)) { PVIRTIO_WDF_BAR pBar = CONTAINING_RECORD(iter, VIRTIO_WDF_BAR, ListEntry); if (pBar->pBase != NULL && !pBar->bPortSpace) { MmUnmapIoSpace(pBar->pBase, pBar->uLength); } ExFreePoolWithTag(pBar, pWdfDriver->MemoryTag); } }
VOID CdUnload( __in PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This routine unload routine for CDFS. Arguments: DriverObject - Supplies the driver object for CDFS. Return Value: None. --*/ { PIRP_CONTEXT IrpContext; PAGED_CODE(); UNREFERENCED_PARAMETER( DriverObject ); // // Free any IRP contexts // while (1) { IrpContext = (PIRP_CONTEXT) PopEntryList( &CdData.IrpContextList) ; if (IrpContext == NULL) { break; } CdFreePool(&IrpContext); } IoFreeWorkItem (CdData.CloseItem); ExDeleteResourceLite( &CdData.DataResource ); ObDereferenceObject (CdData.FileSystemDeviceObject); }
PSINGLE_LIST_ENTRY NTAPI ExInterlockedPopEntryList( IN OUT PSINGLE_LIST_ENTRY ListHead, IN OUT PKSPIN_LOCK Lock) { BOOLEAN Enable; PSINGLE_LIST_ENTRY ListEntry; /* Disable interrupts and acquire the spinlock */ Enable = _ExiDisableInteruptsAndAcquireSpinlock(Lock); /* Pop the first entry from the list */ ListEntry = PopEntryList(ListHead); /* Release the spinlock and restore interrupts */ _ExiReleaseSpinLockAndRestoreInterupts(Lock, Enable); /* Return the entry */ return ListEntry; }
VOID BalloonLeak( IN WDFOBJECT WdfDevice, IN size_t num ) { PPAGE_LIST_ENTRY pPageListEntry; PMDL pPageMdl; PDEVICE_CONTEXT devCtx = GetDeviceContext(WdfDevice); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); num = min(num, PAGE_SIZE/sizeof(PFN_NUMBER)); for (devCtx->num_pfns = 0; devCtx->num_pfns < num; devCtx->num_pfns++) { pPageListEntry = (PPAGE_LIST_ENTRY)PopEntryList(&devCtx->PageListHead); if (pPageListEntry == NULL) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "PopEntryList=NULL\n"); break; } devCtx->pfns_table[devCtx->num_pfns] = pPageListEntry->PagePfn; pPageMdl = pPageListEntry->PageMdl; MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); ExFreeToNPagedLookasideList( &devCtx->LookAsideList, pPageListEntry ); devCtx->num_pages--; } BalloonTellHost(WdfDevice, devCtx->DefVirtQueue); }
VOID BalloonLeak( IN WDFOBJECT WdfDevice, IN size_t num ) { PDEVICE_CONTEXT ctx = GetDeviceContext(WdfDevice); PPAGE_LIST_ENTRY pPageListEntry; PMDL pPageMdl; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> %s\n", __FUNCTION__); pPageListEntry = (PPAGE_LIST_ENTRY)PopEntryList(&ctx->PageListHead); if (pPageListEntry == NULL) { TraceEvents(TRACE_LEVEL_WARNING, DBG_HW_ACCESS, "No list entries.\n"); return; } pPageMdl = pPageListEntry->PageMdl; num = MmGetMdlByteCount(pPageMdl) / PAGE_SIZE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, "Deflate balloon with %d pages.\n", num); ctx->num_pfns = num; ctx->num_pages -= ctx->num_pfns; RtlCopyMemory(ctx->pfns_table, MmGetMdlPfnArray(pPageMdl), ctx->num_pfns * sizeof(PFN_NUMBER)); MmFreePagesFromMdl(pPageMdl); ExFreePool(pPageMdl); ExFreeToNPagedLookasideList(&ctx->LookAsideList, pPageListEntry); BalloonTellHost(WdfDevice, ctx->DefVirtQueue); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- %s\n", __FUNCTION__); }
PINTERNALOVERLAPPEDSTRUCT DOVERLAPPEDSTRUCTMGR::PopOverlappedStruct() /*++ Routine Description: Pops a internal overlapped structure off of the free list and initializes the structure. Arguments: NONE Return Value: A pointer to a internal overlapped structure on success else NULL --*/ { PINTERNALOVERLAPPEDSTRUCT ReturnValue; EnterCriticalSection(&m_overlapped_free_list_lock); ReturnValue = (PINTERNALOVERLAPPEDSTRUCT)PopEntryList(&m_overlapped_free_list); LeaveCriticalSection(&m_overlapped_free_list_lock); if (ReturnValue){ // Init the structure ZeroMemory( ReturnValue, sizeof(INTERNALOVERLAPPEDSTRUCT)); ReturnValue->iolSignature = STRUCTSIGNATURE; } //if return(ReturnValue); }
NTSTATUS NTAPI UserDestroyThreadInfo(struct _ETHREAD *Thread) { PTHREADINFO *ppti; PSINGLE_LIST_ENTRY psle; PPROCESSINFO ppiCurrent; struct _EPROCESS *Process; PTHREADINFO ptiCurrent; Process = Thread->ThreadsProcess; /* Get the Win32 Thread */ ptiCurrent = PsGetThreadWin32Thread(Thread); ASSERT(ptiCurrent); TRACE_CH(UserThread,"Destroying pti 0x%p eThread 0x%p\n", ptiCurrent, Thread); ptiCurrent->TIF_flags |= TIF_INCLEANUP; ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags; ppiCurrent = ptiCurrent->ppi; ASSERT(ppiCurrent); IsRemoveAttachThread(ptiCurrent); ptiCurrent->TIF_flags |= TIF_DONTATTACHQUEUE; ptiCurrent->pClientInfo->dwTIFlags = ptiCurrent->TIF_flags; /* Decrement thread count and check if its 0 */ ppiCurrent->cThreads--; if(ptiCurrent->TIF_flags & TIF_GUITHREADINITIALIZED) { /* Do now some process cleanup that requires a valid win32 thread */ if(ptiCurrent->ppi->cThreads == 0) { /* Check if we have registered the user api hook */ if(ptiCurrent->ppi == ppiUahServer) { /* Unregister the api hook */ UserUnregisterUserApiHook(); } /* Notify logon application to restart shell if needed */ if(ptiCurrent->pDeskInfo) { if(ptiCurrent->pDeskInfo->ppiShellProcess == ppiCurrent) { DWORD ExitCode = PsGetProcessExitStatus(Process); TRACE_CH(UserProcess, "Shell process is exiting (%lu)\n", ExitCode); UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_SHELL_EXITED, ExitCode); ptiCurrent->pDeskInfo->ppiShellProcess = NULL; } } } DceFreeThreadDCE(ptiCurrent); HOOK_DestroyThreadHooks(Thread); EVENT_DestroyThreadEvents(Thread); DestroyTimersForThread(ptiCurrent); KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE); UnregisterThreadHotKeys(ptiCurrent); /* if (IsListEmpty(&ptiCurrent->WindowListHead)) { ERR_CH(UserThread,"Thread Window List is Empty!\n"); } */ co_DestroyThreadWindows(Thread); if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling && ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED) { TRACE_CH(UserThread,"DestroyProcessClasses\n"); /* no process windows should exist at this point, or the function will assert! */ DestroyProcessClasses(ppiCurrent); ppiCurrent->W32PF_flags &= ~W32PF_CLASSESREGISTERED; } IntBlockInput(ptiCurrent, FALSE); IntCleanupThreadCallbacks(ptiCurrent); /* cleanup user object references stack */ psle = PopEntryList(&ptiCurrent->ReferencesList); while (psle) { PUSER_REFERENCE_ENTRY ref = CONTAINING_RECORD(psle, USER_REFERENCE_ENTRY, Entry); TRACE_CH(UserThread,"thread clean: remove reference obj 0x%p\n",ref->obj); UserDereferenceObject(ref->obj); psle = PopEntryList(&ptiCurrent->ReferencesList); } } /* Find the THREADINFO in the PROCESSINFO's list */ ppti = &ppiCurrent->ptiList; while (*ppti != NULL && *ppti != ptiCurrent) { ppti = &((*ppti)->ptiSibling); } /* we must have found it */ ASSERT(*ppti == ptiCurrent); /* Remove it from the list */ *ppti = ptiCurrent->ptiSibling; if (ptiCurrent->KeyboardLayout) UserDereferenceObject(ptiCurrent->KeyboardLayout); if (gptiForeground == ptiCurrent) { // IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0); // IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, NULL, OBJID_WINDOW, CHILDID_SELF, 0); gptiForeground = NULL; } // Fixes CORE-6384 & CORE-7030. /* if (ptiLastInput == ptiCurrent) { if (!ppiCurrent->ptiList) ptiLastInput = gptiForeground; else ptiLastInput = ppiCurrent->ptiList; ERR_CH(UserThread,"DTI: ptiLastInput is Cleared!!\n"); } */ TRACE_CH(UserThread,"Freeing pti 0x%p\n", ptiCurrent); /* Free the THREADINFO */ IntDereferenceThreadInfo(ptiCurrent); return STATUS_SUCCESS; }
VOID VIOSerialPortWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { NTSTATUS status; PVOID InBuf; PVOID buffer; PVIOSERIAL_PORT Port; PWRITE_BUFFER_ENTRY entry; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> %s Request: %p Length: %d\n", __FUNCTION__, Request, Length); PAGED_CODE(); status = WdfRequestRetrieveInputBuffer(Request, Length, &InBuf, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to retrieve input buffer: %x\n", status); WdfRequestComplete(Request, status); return; } Port = RawPdoSerialPortGetData(WdfIoQueueGetDevice(Queue))->port; if (VIOSerialWillWriteBlock(Port)) { WdfRequestComplete(Request, STATUS_CANT_WAIT); return; } status = WdfRequestMarkCancelableEx(Request, VIOSerialPortWriteRequestCancel); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to mark request as cancelable: %x\n", status); WdfRequestComplete(Request, status); return; } buffer = ExAllocatePoolWithTag(NonPagedPool, Length, VIOSERIAL_DRIVER_MEMORY_TAG); if (buffer == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate.\n"); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } entry = (PWRITE_BUFFER_ENTRY)ExAllocatePoolWithTag(NonPagedPool, sizeof(WRITE_BUFFER_ENTRY), VIOSERIAL_DRIVER_MEMORY_TAG); if (entry == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to allocate write buffer entry.\n"); ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); return; } RtlCopyMemory(buffer, InBuf, Length); WdfRequestSetInformation(Request, (ULONG_PTR)Length); entry->Buffer = buffer; PushEntryList(&Port->WriteBuffersList, &entry->ListEntry); Port->PendingWriteRequest = Request; if (VIOSerialSendBuffers(Port, buffer, Length) <= 0) { PSINGLE_LIST_ENTRY removed; TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "Failed to send user's buffer.\n"); ExFreePoolWithTag(buffer, VIOSERIAL_DRIVER_MEMORY_TAG); removed = PopEntryList(&Port->WriteBuffersList); NT_ASSERT(entry == CONTAINING_RECORD(removed, WRITE_BUFFER_ENTRY, ListEntry)); ExFreePoolWithTag(entry, VIOSERIAL_DRIVER_MEMORY_TAG); Port->PendingWriteRequest = NULL; WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE,"<-- %s\n", __FUNCTION__); }
_Must_inspect_result_ NTSTATUS FxPkgIo::ResumeProcessingForPower() /*++ Routine Description: Resumes all PowerManaged queues for automatic I/O processing due to a power event that allows I/O to resume. Non-PowerManaged queues are left alone. Arguments: Return Value: NTSTATUS --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Power resume all queues of WDFDEVICE 0x%p", m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOn); // // Change the state so that new queues created while we // are resuming the existing queues can be in a powered-on state. // m_PowerStateOn = TRUE; // // Change the accepting state so that new queues created while we // are resuming the existing queues can be accept request. // m_QueuesAreShuttingDown = FALSE; Unlock(irql); // // We will power-up the queues in two steps. First we will resume // the power of all the queues and then we will start dispatching I/Os. // This is to avoid a queue being powered up at the begining of the list // trying to forward a request to another queue lower in the list that's // not powered up yet. // for(ple = queueList.Next; ple != NULL; ple = ple->Next) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->ResumeProcessingForPower(); } for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StartPowerTransitionOn(); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } return STATUS_SUCCESS; }
_Must_inspect_result_ NTSTATUS FxPkgIo::StopProcessingForPower( __in FxIoStopProcessingForPowerAction Action ) /*++ Routine Description: Stops all PowerManaged queues automatic I/O processing due to a power event that requires I/O to stop. This is called on a PASSIVE_LEVEL thread that can block until I/O has been stopped, or completed/cancelled. Arguments: Action - FxIoStopProcessingForPowerHold: the function returns when the driver has acknowledged that it has stopped all I/O processing, but may have outstanding "in-flight" requests that have not been completed. FxIoStopProcessingForPowerPurgeManaged: the function returns when all requests from a power managed queue have been completed and/or cancelled., and there are no more in-flight requests. FxIoStopProcessingForPowerPurgeNonManaged: the function returns when all requests from a non-power managed queue have been completed and/or cancelled., and there are no more in-flight requests. Only called during device-remove. Return Value: NTSTATUS --*/ { KIRQL irql; FxIoQueue* queue; SINGLE_LIST_ENTRY queueList, *ple; DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, "Perform %!FxIoStopProcessingForPowerAction! for all queues of " "WDFDEVICE 0x%p", Action, m_Device->GetHandle()); queueList.Next = NULL; Lock(&irql); // // Device is moving into low power state. So any new queues // created after this point would start off as powered off. // m_PowerStateOn = FALSE; // // If queues are shutting down, any new queue created after // this point would not accept any requests. // switch(Action) { case FxIoStopProcessingForPowerPurgeManaged: case FxIoStopProcessingForPowerPurgeNonManaged: m_QueuesAreShuttingDown = TRUE; break; } GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOff); Unlock(irql); // // If the power action is hold then first change the state of all the queues // to PowerStartTransition. This will prevent the queues from dispatching // new requests before we start asking each queue to stop processing // inflight requests. // if(Action == FxIoStopProcessingForPowerHold) { // // Walk the list without popping entries because we need to scan // the list again. // for(ple = queueList.Next; ple != NULL; ple = ple->Next) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StartPowerTransitionOff(); } } // // Ask the queues to stop processing inflight requests. // for (ple = PopEntryList(&queueList); ple != NULL; ple = PopEntryList(&queueList)) { queue = FxIoQueue::_FromPowerSListEntry(ple); queue->StopProcessingForPower(Action); ple->Next = NULL; queue->RELEASE(IO_ITERATOR_POWER_TAG); } return STATUS_SUCCESS; }
static NTSTATUS VirtQueueAddBuffer(IN PDEVICE_CONTEXT Context, IN WDFREQUEST Request, IN size_t Length) { PREAD_BUFFER_ENTRY entry; size_t length; struct virtqueue *vq = Context->VirtQueue; struct VirtIOBufferDescriptor sg; int ret; TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> %!FUNC!"); entry = (PREAD_BUFFER_ENTRY)ExAllocatePoolWithTag(NonPagedPool, sizeof(READ_BUFFER_ENTRY), VIRT_RNG_MEMORY_TAG); if (entry == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Failed to allocate a read entry."); return STATUS_INSUFFICIENT_RESOURCES; } length = min(Length, PAGE_SIZE); entry->Buffer = ExAllocatePoolWithTag(NonPagedPool, length, VIRT_RNG_MEMORY_TAG); if (entry->Buffer == NULL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Failed to allocate a read buffer."); ExFreePoolWithTag(entry, VIRT_RNG_MEMORY_TAG); return STATUS_INSUFFICIENT_RESOURCES; } entry->Request = Request; sg.physAddr = MmGetPhysicalAddress(entry->Buffer); sg.length = (unsigned)length; WdfSpinLockAcquire(Context->VirtQueueLock); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Push %p Request: %p Buffer: %p", entry, entry->Request, entry->Buffer); PushEntryList(&Context->ReadBuffersList, &entry->ListEntry); ret = virtqueue_add_buf(vq, &sg, 0, 1, entry, NULL, 0); if (ret < 0) { PSINGLE_LIST_ENTRY removed; TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Failed to add buffer to virt queue."); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Pop %p Request: %p Buffer: %p", entry, entry->Request, entry->Buffer); removed = PopEntryList(&Context->ReadBuffersList); NT_ASSERT(entry == CONTAINING_RECORD( removed, READ_BUFFER_ENTRY, ListEntry)); ExFreePoolWithTag(entry->Buffer, VIRT_RNG_MEMORY_TAG); ExFreePoolWithTag(entry, VIRT_RNG_MEMORY_TAG); WdfSpinLockRelease(Context->VirtQueueLock); return STATUS_UNSUCCESSFUL; } WdfSpinLockRelease(Context->VirtQueueLock); virtqueue_kick(vq); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- %!FUNC!"); return STATUS_SUCCESS; }
/* 715, "%wsWindows %ws" 716, "%ws Build %ws" 717, "Evaluation copy." 718, "For testing purposes only." 723, "%wsMicrosoft (R) Windows (R) (Build %ws: %ws)" 737, "This copy of Windows is not genuine" 738, "Test Mode" */ BOOL GetWatermarkFromMuiFile(LPTSTR pszFile) { _tcprintf(_T("File name:\t%s\n"), pszFile); if (!PathFileExists(pszFile)) { _tcprintf(_T("File not found!\n")); return FALSE; } // // Check file version, we need to get the language ID of the mui file. // MYVERSIONINFO vi; ZeroMemory(&vi, sizeof(MYVERSIONINFO)); vi.dwSize = sizeof(MYVERSIONINFO); if (!GetDllFileVersion(pszFile, &vi)) { _tcprintf(_T("Fail to get file version info!\n")); return FALSE; } _tcprintf(_T("File version:\t%s\n"), vi.szShortVersion); // // Load mui file to memory // HINSTANCE hInstLib = NULL; hInstLib = LoadLibraryEx(pszFile, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); if( NULL == hInstLib ) { _tcprintf(_T("Fail to open file user32.dll.mui!\n")); return FALSE; } // // Get file type // PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER)((DWORD_PTR)hInstLib - 1); PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS) (pDOSHeader->e_lfanew + (DWORD_PTR)pDOSHeader); _tcprintf(_T("File type:\t")); switch (pNTHeader->FileHeader.Machine) { case IMAGE_FILE_MACHINE_I386: _tcprintf(_T("x86")); break; case IMAGE_FILE_MACHINE_AMD64: _tcprintf(_T("x64")); break; case IMAGE_FILE_MACHINE_IA64: _tcprintf(_T("ia64")); break; default: _tcprintf(_T("Unknown\nThis is not a valid file.\n")); FreeLibrary(hInstLib); return FALSE; } UINT uStringID; UINT uStringIDS[] = {715, 716, 717, 718, 738, 723, 737}; BOOL bHasPatched = FALSE; UINT i = 0; UINT uMatchingString = 0; // Create string info lists SINGLE_LIST_ENTRY StringsHead; PSINGLE_LIST_ENTRY psLink; PRES_STRING_INFO pStrInfo; StringsHead.Next = NULL; _tcprintf(_T("\n\n ID String Offset Len Mod")); _tcprintf( _T("\n----- ---------------------------------------------------- ------ --- ---")); for (i=0; i < sizeof(uStringIDS)/sizeof(UINT); i++) { // Add a entry pStrInfo = (PRES_STRING_INFO)MALLOC(sizeof(RES_STRING_INFO)); ZeroMemory(pStrInfo, sizeof(RES_STRING_INFO)); pStrInfo->uStringID = uStringIDS[i]; LoadStringExx(hInstLib, (WORD)vi.wLangID, pStrInfo); if (lstrlen(pStrInfo->pszText) > 0) { uMatchingString++; } _tcprintf(_T("\n%5d %s"), pStrInfo->uStringID, pStrInfo->pszText); gotoX(61); _tcprintf(_T("0x%4X %3d"), pStrInfo->dwFileOffset, pStrInfo->dwBytes); PushEntryList(&StringsHead, &(pStrInfo->link)); } // for(i) // importance FreeLibrary(hInstLib); _tcprintf(_T("\n\n")); if ( (uMatchingString > 0) && (StringsHead.Next != NULL) ) { _tcprintf(_T("Do you want to patch this file?\n")); _tcprintf(_T(" (Y=Yes / N=No)\n:")); int iChoice = getchar(); if ( (iChoice == _T('y')) || (iChoice == _T('Y')) ) { TCHAR szFileBackup[MAX_PATH]; StringCbCopy(szFileBackup, sizeof(szFileBackup), pszFile); StringCbCat(szFileBackup, sizeof(szFileBackup), _T(".backup")); // make a backup CopyFile(pszFile, szFileBackup, FALSE); // In real life, if you want to patch \windows\system32\en-us\user32.dll.mui, // because the file is in using, you must copy a temp file to do ZeroWatermarkFromMuiFile(). // Last, using MoveFileEx() to replace the file. if (ZeroWatermarkFromMuiFile(pszFile, &StringsHead)) { _tcprintf(_T("\nPatch OK!\n")); } else { _tcprintf(_T("\nFail to patch.\n")); } } // choice y } else { _tcprintf(_T("Watermark string is not found, no need to patch.\n")); } // // Removes all string infos, free memory // psLink = PopEntryList(&StringsHead); while(psLink) { pStrInfo = CONTAINING_RECORD(psLink, RES_STRING_INFO, link); // free memory if (pStrInfo->pszText) FREE((LPVOID)(pStrInfo->pszText)); FREE((LPVOID)pStrInfo); // Removes the first entry psLink = PopEntryList(&StringsHead); } // while(psLink) return TRUE; } // GetWatermarkFromMuiFile
/************************************************************************ *************************************** PgDumpTimerTable ************************************************************************* Description: All PatchGuard 2 related timers will wear the "suspect" sttribute. ATTENTION: The code uses undocumented kernel APIs. Please keep in mind that you shouldn't change the code logic and remember that during enumeration your code will run at DISPATCH_LEVEL! */ NTSTATUS PgDumpTimerTable() { KIRQL OldIrql; ULONG Index; PKSPIN_LOCK_QUEUE LockQueue; PKTIMER_TABLE_ENTRY TimerListHead; PLIST_ENTRY TimerList; PKTIMER Timer; PKDPC TimerDpc; CHAR LogEntryText[2048]; NTSTATUS Result = STATUS_SUCCESS; HANDLE hLogFile; UNICODE_STRING LogFileName; OBJECT_ATTRIBUTES ObjAttr; IO_STATUS_BLOCK IOStatus; ULONG LogEntryTextLen; SINGLE_LIST_ENTRY LogListHead = {NULL}; PSINGLE_LIST_ENTRY LogList; LOGENTRY* LogEntry; ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); /* Open log file... */ RtlInitUnicodeString(&LogFileName, L"\\??\\C:\\patchguard.log"); InitializeObjectAttributes( &ObjAttr, &LogFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL) if(!NT_SUCCESS(Result = ZwCreateFile( &hLogFile, GENERIC_WRITE, &ObjAttr, &IOStatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, 0))) { KdPrint(("\r\n" "ERROR: Unable to open file \"\\??\\C:\\patchguard.log\". (NTSTATUS: 0x%p)\r\n", (void*)Result)); return Result; } /* Lock the dispatcher database and loop through the timer list... */ Result = STATUS_SUCCESS; OldIrql = KiAcquireDispatcherLockRaiseToSynch(); for(Index = 0; Index < TIMER_TABLE_SIZE; Index++) { // we have to emulate the windows timer bug "Index & 0xFF" for this to work... LockQueue = KeTimerIndexToLockQueue((UCHAR)(Index & 0xFF)); KeAcquireQueuedSpinLockAtDpcLevel(LockQueue); // now we can work with the timer list... TimerListHead = &KiTimerTableListHead[Index]; TimerList = TimerListHead->Entry.Flink; while(TimerList != (PLIST_ENTRY)TimerListHead) { Timer = CONTAINING_RECORD(TimerList, KTIMER, TimerListEntry); TimerDpc = PgDeobfuscateTimerDpc(Timer); TimerList = TimerList->Flink; if(TimerDpc != NULL) { memset(LogEntryText, 0, sizeof(LogEntryText)); LogEntryTextLen = _snprintf(LogEntryText, sizeof(LogEntryText) - 1, "<timer address=\"%p\" index=\"%d\" period=\"0x%p\" hand=\"%d\" duetime=\"0x%p\">\r\n" "%s" " <dpc>\r\n" " <DeferredContext value=\"0x%p\">%s</DeferredContext>\r\n" " <DeferredRoutine>0x%p</DeferredRoutine>\r\n" " <DpcListBlink value=\"0x%p\">%s</DpcListBlink>\r\n" " <DpcListFlink value=\"0x%p\">%s</DpcListFlink>\r\n" " <DpcData value=\"0x%p\">%s</DpcData>\r\n" " <Importance>%d</Importance>\r\n" " <Number>%d</Number>\r\n" " <SystemArgument1 value=\"0x%p\">%s</SystemArgument1>\r\n" " <SystemArgument2 value=\"0x%p\">%s</SystemArgument2>\r\n" " <Type>%d</Type>\r\n" " </dpc>\r\n" "</timer>\r\n\r\n", Timer, Index, (ULONGLONG)Timer->Period, (ULONG)Timer->Header.Hand, Timer->DueTime.QuadPart, PgIsPatchGuardContext(TimerDpc->DeferredContext)?" <SUSPECT>true</SUSPECT>\t\n":"", TimerDpc->DeferredContext, PointerToString(TimerDpc->DeferredContext), TimerDpc->DeferredRoutine, TimerDpc->DpcListEntry.Blink, PointerToString(TimerDpc->DpcListEntry.Blink), TimerDpc->DpcListEntry.Flink, PointerToString(TimerDpc->DpcListEntry.Flink), TimerDpc->DpcData, PointerToString(TimerDpc->DpcData), (ULONG)TimerDpc->Importance, (ULONG)TimerDpc->Number, TimerDpc->SystemArgument1, PointerToString(TimerDpc->SystemArgument1), TimerDpc->SystemArgument2, PointerToString(TimerDpc->SystemArgument2), (ULONG)TimerDpc->Type ); // allocate memory and add log entry to list... if((LogEntry = (LOGENTRY*)ExAllocatePool(NonPagedPool, sizeof(LOGENTRY) + LogEntryTextLen + 1)) == NULL) { KeReleaseQueuedSpinLockFromDpcLevel(LockQueue); Result = STATUS_NO_MEMORY; DbgPrint("\r\n" "WARNING: Not enough non-paged memory to write suspect timer to file. Aborting enumeration...\r\n"); break; } LogEntry->Text = (CHAR*)(LogEntry + 1); LogEntry->Length = LogEntryTextLen; memcpy(LogEntry->Text, LogEntryText, LogEntryTextLen); PushEntryList(&LogListHead, &LogEntry->List); } } KeReleaseQueuedSpinLockFromDpcLevel(LockQueue); } KiReleaseDispatcherLockFromSynchLevel(); KiExitDispatcher(OldIrql); KdPrint(("\r\n" "INFORMATION: Completed PatchGuard scan...\r\n")); /* Loop through the log entries and flush them to disk... In case of an error during enumeration this actually won't write any files, but just free allocated memory... */ LogList = PopEntryList(&LogListHead); while(LogList != NULL) { LogEntry = CONTAINING_RECORD(LogList, LOGENTRY, List); if(NT_SUCCESS(Result)) { Result = ZwWriteFile( hLogFile, NULL, NULL, NULL, &IOStatus, LogEntry->Text, LogEntry->Length, NULL, NULL); } ExFreePool(LogEntry); LogList = PopEntryList(&LogListHead); } ZwClose(hLogFile); return Result; }