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); }
// Buffer the log entry to the log buffer. _Use_decl_annotations_ static NTSTATUS LogpBufferMessage(const char *message, LogBufferInfo *info) { NT_ASSERT(info); // Acquire a spin lock to add the log safely. KLOCK_QUEUE_HANDLE lock_handle = {}; const auto old_irql = KeGetCurrentIrql(); if (old_irql < DISPATCH_LEVEL) { KeAcquireInStackQueuedSpinLock(&info->spin_lock, &lock_handle); } else { KeAcquireInStackQueuedSpinLockAtDpcLevel(&info->spin_lock, &lock_handle); } NT_ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL); // Copy the current log to the buffer. SIZE_T used_buffer_size = info->log_buffer_tail - info->log_buffer_head; auto status = RtlStringCchCopyA(const_cast<char *>(info->log_buffer_tail), kLogpBufferUsableSize - used_buffer_size, message); // Update info.log_max_usage if necessary. if (NT_SUCCESS(status)) { const auto message_length = strlen(message) + 1; info->log_buffer_tail += message_length; used_buffer_size += message_length; if (used_buffer_size > info->log_max_usage) { info->log_max_usage = used_buffer_size; // Update } } else { info->log_max_usage = kLogpBufferSize; // Indicates overflow } *info->log_buffer_tail = '\0'; if (old_irql < DISPATCH_LEVEL) { KeReleaseInStackQueuedSpinLock(&lock_handle); } else { KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_handle); } return status; }
// Releases a spin lock ScopedSpinLockAtDpc::~ScopedSpinLockAtDpc() { KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_handle_); }
NTSTATUS InsertNBs( _Inout_ KKDRV_QUEUE_DATA *queueData, _In_ NET_BUFFER_LIST *head ) { NTSTATUS status = STATUS_SUCCESS; KLOCK_QUEUE_HANDLE lockHandle; NET_BUFFER_LIST *nbl = head; NET_BUFFER *nb; while (nbl) { nb = NET_BUFFER_LIST_FIRST_NB(nbl); while (nb) { PVOID data; ULONG dataLength = NET_BUFFER_DATA_LENGTH(nb); PKKDRV_PACKET packet = (PKKDRV_PACKET)ExAllocatePoolWithTag( NonPagedPool, KKDRV_PACKET_SIZE + dataLength, KKDRV_TAG ); if (packet == NULL) { return STATUS_INSUFFICIENT_RESOURCES; }; packet->dataLength = dataLength; data = NdisGetDataBuffer(nb, dataLength, NULL, 1, 0); if (data == NULL) { NdisGetDataBuffer(nb, dataLength, &packet->data, 1, 0); } else { RtlCopyMemory(&(packet->data), data, dataLength); } KeAcquireInStackQueuedSpinLockAtDpcLevel( &queueData->queueLock, &lockHandle ); InsertTailList(&queueData->queue, &packet->entry); queueData->queueLength++; if (queueData->queueLength > queueData->queueLengthMax) { PLIST_ENTRY entry = RemoveHeadList(&queueData->queue); ExFreePoolWithTag(entry, KKDRV_TAG); queueData->queueLength--; } KeReleaseInStackQueuedSpinLockFromDpcLevel( &lockHandle ); nb = nb->Next; } nbl = nbl->Next; } return status; }
VOID FASTCALL KeWaitForGate ( __inout PKGATE Gate, __in KWAIT_REASON WaitReason, __in KPROCESSOR_MODE WaitMode ) /*++ Routine Description: This function waits until the signal state of a gate object is set. If the state of the gate object is signaled when the wait is executed, then no wait will occur. Arguments: Gate - Supplies a pointer to a dispatcher object of type Gate. WaitReason - Supplies the reason for the wait. WaitMode - Supplies the processor mode in which the wait is to occur. Return Value: None. --*/ { PKTHREAD CurrentThread; KLOCK_QUEUE_HANDLE LockHandle; PKQUEUE Queue; PKWAIT_BLOCK WaitBlock; NTSTATUS WaitStatus; ASSERT_GATE(Gate); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); // // Raise IRQL to SYNCH_LEVEL and acquire the APC queue lock. // CurrentThread = KeGetCurrentThread(); do { KeAcquireInStackQueuedSpinLockRaiseToSynch(&CurrentThread->ApcQueueLock, &LockHandle); // // Test to determine if a kernel APC is pending. // // If a kernel APC is pending, the special APC disable count is zero, // and the previous IRQL was less than APC_LEVEL, then a kernel APC // was queued by another processor just after IRQL was raised to // SYNCH_LEVEL, but before the APC queue lock was acquired. // // N.B. This can only happen in a multiprocessor system. // if (CurrentThread->ApcState.KernelApcPending && (CurrentThread->SpecialApcDisable == 0) && (LockHandle.OldIrql < APC_LEVEL)) { // // Unlock the APC queue lock and lower IRQL to its previous value. // An APC interrupt will immediately occur which will result in // the delivery of the kernel APC if possible. // KeReleaseInStackQueuedSpinLock(&LockHandle); continue; } // // If the current thread is associated with a queue object, then // acquire the dispatcher lock. // if ((Queue = CurrentThread->Queue) != NULL) { KiLockDispatcherDatabaseAtSynchLevel(); } // // Acquire the thread lock and the object lock. // // If the object is already signaled, then clear the signaled state, // release the object lock, release the thread lock, and lower IRQL // to its previous value. Otherwise, set the thread state to gate // wait, set the address of the gate object, insert the thread in the // object wait list, set context swap busy, release the object lock, // release the thread lock, and switch to a new thread. // KiAcquireThreadLock(CurrentThread); KiAcquireKobjectLock(Gate); if (Gate->Header.SignalState != 0) { Gate->Header.SignalState = 0; KiReleaseKobjectLock(Gate); KiReleaseThreadLock(CurrentThread); if (Queue != NULL) { KiUnlockDispatcherDatabaseFromSynchLevel(); } KeReleaseInStackQueuedSpinLock(&LockHandle); break; } else { WaitBlock = &CurrentThread->WaitBlock[0]; WaitBlock->Object = Gate; WaitBlock->Thread = CurrentThread; CurrentThread->WaitMode = WaitMode; CurrentThread->WaitReason = WaitReason; CurrentThread->WaitIrql = LockHandle.OldIrql; CurrentThread->State = GateWait; CurrentThread->GateObject = Gate; InsertTailList(&Gate->Header.WaitListHead, &WaitBlock->WaitListEntry); KiReleaseKobjectLock(Gate); KiSetContextSwapBusy(CurrentThread); KiReleaseThreadLock(CurrentThread); // // If the current thread is associated with a queue object, then // activate another thread if possible. // if (Queue != NULL) { if ((Queue = CurrentThread->Queue) != NULL) { KiActivateWaiterQueue(Queue); } KiUnlockDispatcherDatabaseFromSynchLevel(); } KeReleaseInStackQueuedSpinLockFromDpcLevel(&LockHandle); WaitStatus = (NTSTATUS)KiSwapThread(CurrentThread, KeGetCurrentPrcb()); if (WaitStatus == STATUS_SUCCESS) { return; } } } while (TRUE); return; }