1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxPkgIo.cpp 8 9 Abstract: 10 11 This module implements the I/O package for the driver frameworks. 12 13 Author: 14 15 16 17 Environment: 18 19 Both kernel and user mode 20 21 Revision History: 22 23 24 25 --*/ 26 27 #include "ioprivshared.hpp" 28 29 // Tracing support 30 extern "C" { 31 #if defined(EVENT_TRACING) 32 #include "FxPkgIo.tmh" 33 #endif 34 } 35 36 // 37 // This package is initialized by the FxPkgIo::Install virtual method 38 // being invoked. 39 // 40 // A reference is held on it by the FxDevice which owns it. When the 41 // FxDevice is destroyed, its destructor FxDevice::~FxDevice will release 42 // its reference to this package, so that FxPkgIo::~FxPkgIo can run. 43 // 44 // There is no other package remove, or un-install call. 45 // 46 47 FxPkgIo::FxPkgIo( 48 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 49 __in CfxDevice *Device 50 ) : 51 FxPackage(FxDriverGlobals, Device, FX_TYPE_PACKAGE_IO), 52 m_InCallerContextCallback(FxDriverGlobals) 53 { 54 LARGE_INTEGER tickCount; 55 56 m_Device = Device; 57 58 m_DefaultQueue = NULL; 59 60 RtlZeroMemory(m_DispatchTable, sizeof(m_DispatchTable)); 61 62 m_Filter = FALSE; 63 64 m_PowerStateOn = FALSE; 65 66 m_QueuesAreShuttingDown = FALSE; 67 68 InitializeListHead(&m_IoQueueListHead); 69 70 InitializeListHead(&m_DynamicDispatchInfoListHead); 71 72 Mx::MxQueryTickCount(&tickCount); 73 74 m_RandomSeed = tickCount.LowPart; 75 76 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, 77 "Constructed FxPkgIo 0x%p",this); 78 } 79 80 FxPkgIo::~FxPkgIo() 81 { 82 PLIST_ENTRY next; 83 84 m_DefaultQueue = NULL; 85 86 m_Device = NULL; 87 88 while (!IsListEmpty(&m_DynamicDispatchInfoListHead)) { 89 next = RemoveHeadList(&m_DynamicDispatchInfoListHead); 90 FxIrpDynamicDispatchInfo* info; 91 info = CONTAINING_RECORD(next, FxIrpDynamicDispatchInfo, ListEntry); 92 InitializeListHead(next); 93 delete info; 94 } 95 96 ASSERT(IsListEmpty(&m_IoQueueListHead)); 97 98 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, 99 "Destroyed FxPkgIo 0x%p",this); 100 } 101 102 _Must_inspect_result_ 103 NTSTATUS 104 FxPkgIo::Dispatch( 105 __inout MdIrp Irp 106 ) 107 { 108 FxIrp fxIrp(Irp); 109 FX_TRACK_DRIVER(GetDriverGlobals()); 110 111 DoTraceLevelMessage( 112 GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, 113 "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ!, IRP_MN %x, IRP 0x%p", 114 m_Device->GetHandle(), m_Device->GetDeviceObject(), 115 fxIrp.GetMajorFunction(), 116 fxIrp.GetMinorFunction(), Irp); 117 118 return DispatchStep1(Irp, m_DynamicDispatchInfoListHead.Flink); 119 } 120 121 _Must_inspect_result_ 122 NTSTATUS 123 FX_VF_METHOD(FxPkgIo, VerifyDispatchContext) ( 124 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, 125 _In_ WDFCONTEXT DispatchContext 126 ) 127 { 128 NTSTATUS status = STATUS_SUCCESS; 129 BOOLEAN ctxValid; 130 PLIST_ENTRY next; 131 132 PAGED_CODE_LOCKED(); 133 134 // 135 // Make sure context is valid. 136 // 137 ctxValid = (PLIST_ENTRY)DispatchContext == 138 &m_DynamicDispatchInfoListHead ? 139 TRUE : FALSE; 140 141 for (next = m_DynamicDispatchInfoListHead.Flink; 142 next != &m_DynamicDispatchInfoListHead; 143 next = next->Flink) { 144 if ((PLIST_ENTRY)DispatchContext == next) { 145 ctxValid = TRUE; 146 break; 147 } 148 } 149 150 if (FALSE == ctxValid) { 151 status = STATUS_INVALID_PARAMETER; 152 DoTraceLevelMessage( 153 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 154 "DispatchContext 0x%p is invalid, %!STATUS!", 155 DispatchContext, status); 156 FxVerifierDbgBreakPoint(FxDriverGlobals); 157 } 158 159 return status; 160 } 161 162 _Must_inspect_result_ 163 NTSTATUS 164 __fastcall 165 FxPkgIo::DispatchStep1( 166 __inout MdIrp Irp, 167 __in WDFCONTEXT DispatchContext 168 ) 169 /*++ 170 171 Routine Description: 172 173 Checks for any registered dynamic dispatch callbacks that handles this type of request, else 174 selects the default queue based on the IRP's major code. 175 176 Arguments: 177 178 Irp - WDM request. 179 180 DispatchContext - Is the next FxIrpDynamicDispatchInfo element. 181 182 Return Value: 183 184 Irp's status. 185 186 --*/ 187 188 { 189 NTSTATUS status; 190 FxIrp fxIrp(Irp); 191 192 ASSERT(((UCHAR)(ULONG_PTR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); 193 194 ASSERT(fxIrp.GetMajorFunction() <= IRP_MJ_MAXIMUM_FUNCTION); 195 196 // 197 // Look for I/O dynamic dispatch callbacks. 198 // 199 if ((PLIST_ENTRY)DispatchContext != &m_DynamicDispatchInfoListHead) { 200 int index; 201 index = FxIrpDynamicDispatchInfo::Mj2Index(fxIrp.GetMajorFunction()); 202 203 // 204 // Only read/writes/ctrls/internal_ctrls IRPs are allowed, i.e., request cannot 205 // IRP type in its callback. 206 // 207 if (index >= (int)FxIrpDynamicDispatchInfo::DynamicDispatchMax) { 208 status = STATUS_INVALID_PARAMETER; 209 DoTraceLevelMessage( 210 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, 211 "Driver cannot change the IRP type in its dispatch " 212 "callback Irp 0x%p, %!IRPMJ!, IRP_MN %x, Device 0x%p, " 213 "%!STATUS!", 214 Irp, fxIrp.GetMajorFunction(), fxIrp.GetMinorFunction(), 215 m_Device->GetHandle(), status); 216 FxVerifierDbgBreakPoint(GetDriverGlobals()); 217 goto CompleteIrp; 218 } 219 220 // 221 // Verifier checks. 222 // 223 status = VerifyDispatchContext(GetDriverGlobals(), DispatchContext); 224 if( !NT_SUCCESS(status)){ 225 goto CompleteIrp; 226 } 227 228 do { 229 FxIrpDynamicDispatchInfo* info; 230 231 info = CONTAINING_RECORD(DispatchContext, 232 FxIrpDynamicDispatchInfo, 233 ListEntry); 234 // 235 // Advance to next node. 236 // 237 DispatchContext = (WDFCONTEXT)(((PLIST_ENTRY)DispatchContext)->Flink); 238 ASSERT(((UCHAR)(ULONG_PTR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); 239 240 ASSERT(fxIrp.GetMajorFunction() == IRP_MJ_READ || 241 fxIrp.GetMajorFunction() == IRP_MJ_WRITE || 242 fxIrp.GetMajorFunction() == IRP_MJ_DEVICE_CONTROL || 243 fxIrp.GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL); 244 245 // 246 // If registered, invoke dispatch callback for this major function. 247 // 248 ASSERT(index < (int)FxIrpDynamicDispatchInfo::DynamicDispatchMax); 249 if (NULL != info->Dispatch[index].EvtDeviceDynamicDispatch){ 250 return info->Dispatch[index].EvtDeviceDynamicDispatch( 251 m_Device->GetHandle(), 252 fxIrp.GetMajorFunction(), 253 fxIrp.GetMinorFunction(), 254 fxIrp.GetParameterIoctlCode(), 255 info->Dispatch[index].DriverContext, 256 reinterpret_cast<PIRP> (fxIrp.GetIrp()), 257 (WDFCONTEXT)((ULONG_PTR)DispatchContext | 258 FX_IN_DISPATCH_CALLBACK) 259 ); 260 } 261 } while ((PLIST_ENTRY)DispatchContext != 262 &m_DynamicDispatchInfoListHead); 263 } 264 265 // 266 // Only now push these local variables on the stack, this is to keep the 267 // stack from growing unnecessarily in the dynamic dispatch path above. 268 // 269 FxIoQueue* queue; 270 FxIoInCallerContext* ioInCallerCtx; 271 272 // 273 // Get the queue from the dispatch-table 274 // 275 queue = m_DispatchTable[fxIrp.GetMajorFunction()]; 276 if (queue == NULL) { 277 ioInCallerCtx = GetIoInCallerContextCallback(NULL); 278 if (ioInCallerCtx->m_Method == NULL) { 279 // 280 // No queue configured yet, fail request unless the driver is a filter. 281 // 282 if (m_Filter) { 283 goto Forward; 284 } 285 286 status = STATUS_INVALID_DEVICE_REQUEST; 287 DoTraceLevelMessage( 288 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, 289 "No queue configured for WDFDEVICE 0x%p, failing IRP 0x%p," 290 " %!STATUS!", 291 m_Device->GetHandle(), Irp, status); 292 293 goto CompleteIrp; 294 } 295 } 296 else { 297 ioInCallerCtx = GetIoInCallerContextCallback(queue->GetCxDeviceInfo()); 298 } 299 300 // 301 // If the driver is filter and queue is a default-queue then before 302 // calling the queue, we should make sure the queue can dispatch 303 // requests to the driver. If the queue cannot dispatch request, 304 // we should forward it down to the lower driver ourself. 305 // This is to cover the scenario where the driver has registered only 306 // type specific handler and expect the framework to auto-forward other 307 // requests. 308 // 309 if (m_Filter && 310 ioInCallerCtx->m_Method == NULL && 311 queue == m_DefaultQueue && 312 queue->IsIoEventHandlerRegistered((WDF_REQUEST_TYPE)fxIrp.GetMajorFunction()) == FALSE) { 313 // 314 // Default queue doesn't have callback events registered to 315 // handle this request. So forward it down. 316 // 317 goto Forward; 318 } 319 320 // 321 // Finally queue request. 322 // 323 return DispatchStep2(Irp, ioInCallerCtx, queue); 324 325 Forward: 326 327 fxIrp.SkipCurrentIrpStackLocation(); 328 return fxIrp.CallDriver(m_Device->GetAttachedDevice()); 329 330 CompleteIrp: 331 332 fxIrp.SetStatus(status); 333 fxIrp.SetInformation(0); 334 fxIrp.CompleteRequest(IO_NO_INCREMENT); 335 336 return status; 337 } 338 339 _Must_inspect_result_ 340 NTSTATUS 341 __fastcall 342 FxPkgIo::DispatchStep2( 343 __inout MdIrp Irp, 344 __in_opt FxIoInCallerContext* IoInCallerCtx, 345 __in_opt FxIoQueue* Queue 346 ) 347 { 348 NTSTATUS status; 349 FxRequest* request; 350 BOOLEAN isForwardProgressQueue; 351 BOOLEAN inCriticalRegion; 352 PWDF_OBJECT_ATTRIBUTES reqAttribs; 353 FxIrp fxIrp(Irp); 354 355 request = NULL; 356 inCriticalRegion = FALSE; 357 isForwardProgressQueue = Queue != NULL && Queue->IsForwardProgressQueue(); 358 359 ASSERT(fxIrp.GetMajorFunction() <= IRP_MJ_MAXIMUM_FUNCTION); 360 ASSERT((IoInCallerCtx != NULL && IoInCallerCtx->m_Method != NULL) || 361 Queue != NULL); 362 // 363 // The request inserted into the queue can be retrieved and processed 364 // by an arbitrary thread. So we need to make sure that such a thread doesn't 365 // get suspended and deadlock the driver and potentially the system by 366 // entering critical region.The KeEnterCriticalRegion temporarily disables 367 // the delivery of normal kernel APCs used to suspend a thread. 368 // Kernel APCs queued to this thread will get executed when we leave the 369 // critical region. 370 // 371 if (Mx::MxGetCurrentIrql() <= APC_LEVEL) { 372 Mx::MxEnterCriticalRegion(); 373 inCriticalRegion = TRUE; 374 } 375 376 if (Queue != NULL && Queue->GetCxDeviceInfo() != NULL) { 377 reqAttribs = &Queue->GetCxDeviceInfo()->RequestAttributes; 378 } 379 else { 380 reqAttribs = m_Device->GetRequestAttributes(); 381 } 382 383 status = FxRequest::_CreateForPackage(m_Device, reqAttribs, Irp, &request); 384 385 // 386 // Check if it is forward progress queue and the EnhancedVerifierOption for 387 // testing forward progress are set. 388 // 389 if (isForwardProgressQueue && 390 NT_SUCCESS(status) && 391 IsFxVerifierTestForwardProgress(GetDriverGlobals())) { 392 // 393 // This function returns STATUS_INSUFFICIENT_RESOURCES 394 // if testing forward progress is enabled and free's the passed in request. 395 // 396 status = VerifierFreeRequestToTestForwardProgess(request); 397 } 398 399 if (!NT_SUCCESS(status)) { 400 if (m_Filter && Queue == NULL) { 401 goto CompleteIrp; 402 } 403 404 if (isForwardProgressQueue) { 405 status = Queue->GetReservedRequest(Irp, &request); 406 if (status == STATUS_PENDING) { 407 goto IrpIsGone; 408 } 409 else if (!NT_SUCCESS(status)) { 410 goto CompleteIrp; 411 } 412 } 413 else { 414 // 415 // Fail the request 416 // 417 DoTraceLevelMessage( 418 GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, 419 "Could not create WDFREQUEST, %!STATUS!", status); 420 421 goto CompleteIrp; 422 } 423 } 424 else { 425 if (isForwardProgressQueue) { 426 status = Queue->InvokeAllocateResourcesCallback(request); 427 if (!NT_SUCCESS(status)) { 428 // 429 // Failure of the callback means the driver wasn't able to 430 // allocate resources for the request. In that case free the 431 // request allocated earlier and use the reserved one. 432 // 433 request->FreeRequest(); 434 request = NULL; 435 436 status = Queue->GetReservedRequest(Irp, &request); 437 if (status == STATUS_PENDING) { 438 goto IrpIsGone; 439 } 440 else if (!NT_SUCCESS(status)) { 441 goto CompleteIrp; 442 } 443 } 444 } 445 } 446 447 // 448 // Since we can't guarantee the callback to be called in the context of the 449 // caller for reserved requests, we will skip calling InCallerContextCallback 450 // for reserverd request. 451 // 452 if (IoInCallerCtx != NULL && 453 IoInCallerCtx->m_Method != NULL && 454 request->IsReserved() == FALSE) { 455 456 request->SetInternalContext(Queue); 457 status = DispathToInCallerContextCallback(IoInCallerCtx, request, Irp); 458 459 // 460 // The driver is responsible for calling WdfDeviceEnqueueRequest to 461 // insert it back into the I/O processing pipeline, or completing it. 462 // 463 goto IrpIsGone; 464 } 465 466 ASSERT(Queue != NULL); 467 status = Queue->QueueRequest(request); 468 goto IrpIsGone; 469 470 CompleteIrp: 471 472 fxIrp.SetStatus(status); 473 fxIrp.SetInformation(0); 474 fxIrp.CompleteRequest(IO_NO_INCREMENT); 475 // 476 // fallthrough 477 // 478 IrpIsGone: 479 480 if (inCriticalRegion) { 481 Mx::MxLeaveCriticalRegion(); 482 } 483 484 return status; 485 } 486 487 _Must_inspect_result_ 488 NTSTATUS 489 FxPkgIo::InitializeDefaultQueue( 490 __in CfxDevice * Device, 491 __inout FxIoQueue * Queue 492 ) 493 494 /*++ 495 496 Routine Description: 497 498 Make the input queue as the default queue. There can be 499 only one queue as the default queue. 500 501 The default queue is the place all requests go to 502 automatically if a specific queue was not configured 503 for them. 504 505 Arguments: 506 507 508 Return Value: 509 510 NTSTATUS 511 512 --*/ 513 { 514 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 515 ULONG index; 516 517 if (m_DefaultQueue != NULL) { 518 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 519 "Default Queue Already Configured for " 520 "FxPkgIo 0x%p, WDFDEVICE 0x%p %!STATUS!",this, 521 Device->GetHandle(), STATUS_UNSUCCESSFUL); 522 return STATUS_UNSUCCESSFUL; 523 } 524 525 for (index=0; index <= IRP_MJ_MAXIMUM_FUNCTION; index++) { 526 if (m_DispatchTable[index] == NULL) { 527 m_DispatchTable[index] = Queue; 528 } 529 } 530 531 m_DefaultQueue = Queue; 532 533 // 534 // Default queue can't be deleted. So mark the object to fail WdfObjectDelete on 535 // the default queue. 536 // 537 Queue->MarkNoDeleteDDI(); 538 return STATUS_SUCCESS; 539 } 540 541 __inline 542 FxDriver* 543 FxPkgIo::GetDriver( 544 VOID 545 ) 546 { 547 return m_Device->GetDriver(); 548 } 549 550 _Must_inspect_result_ 551 NTSTATUS 552 FX_VF_METHOD(FxPkgIo, VerifyEnqueueRequestUpdateFlags) ( 553 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, 554 _In_ FxRequest* Request, 555 _Inout_ SHORT* OrigVerifierFlags 556 ) 557 { 558 NTSTATUS status = STATUS_SUCCESS; 559 560 PAGED_CODE_LOCKED(); 561 562 KIRQL irql; 563 564 Request->Lock(&irql); 565 566 *OrigVerifierFlags = Request->GetVerifierFlagsLocked(); 567 568 status = Request->VerifyRequestIsInCallerContext(FxDriverGlobals); 569 if (NT_SUCCESS(status)) { 570 status = Request->VerifyRequestIsDriverOwned(FxDriverGlobals); 571 } 572 573 if (NT_SUCCESS(status)) { 574 Request->ClearVerifierFlagsLocked( 575 FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT | 576 FXREQUEST_FLAG_DRIVER_OWNED); 577 } 578 579 Request->Unlock(irql); 580 return status; 581 } 582 583 VOID 584 FX_VF_METHOD(FxPkgIo, VerifyEnqueueRequestRestoreFlags) ( 585 _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, 586 _In_ FxRequest* Request, 587 _In_ SHORT OrigVerifierFlags 588 ) 589 { 590 UNREFERENCED_PARAMETER(FxDriverGlobals); 591 KIRQL irql; 592 593 PAGED_CODE_LOCKED(); 594 595 Request->Lock(&irql); 596 Request->ClearVerifierFlagsLocked(~OrigVerifierFlags); 597 Request->SetVerifierFlagsLocked(OrigVerifierFlags); 598 Request->Unlock(irql); 599 } 600 601 602 // 603 // This inserts a request into the I/O processing pipeline 604 // 605 _Must_inspect_result_ 606 NTSTATUS 607 FxPkgIo::EnqueueRequest( 608 __in CfxDevice* Device, 609 __inout FxRequest* pRequest 610 ) 611 { 612 NTSTATUS status; 613 FxIoQueue* pQueue; 614 FxIrp* Irp = NULL; 615 FxRequestCompletionState oldState; 616 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 617 SHORT origVerifierFlags = 0; 618 619 // 620 // Request is owned by the driver, and has a reference count of == 1 621 // (or > 1 if EvtIoInCallerContext callback took an additional reference), 622 // with a FxPkgIoInProcessRequestComplete callback registered. 623 // 624 ASSERT(pRequest->GetRefCnt() >= 1); 625 626 Irp = pRequest->GetFxIrp(); 627 628 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, 629 "WDFREQUEST 0x%p", pRequest->GetObjectHandle()); 630 631 status = VerifyEnqueueRequestUpdateFlags(FxDriverGlobals, 632 pRequest, 633 &origVerifierFlags); 634 if (!NT_SUCCESS(status)) { 635 return status; 636 } 637 638 // 639 // Get the associated queue 640 // 641 pQueue = (FxIoQueue*) pRequest->GetInternalContext(); 642 if (NULL == pQueue) { 643 pQueue = m_DispatchTable[Irp->GetMajorFunction()]; 644 if (pQueue == NULL) { 645 // 646 // No queue configured yet, fail request unless the driver is a filter. 647 // 648 if (m_Filter) { 649 goto Forward; 650 } 651 652 status = STATUS_INVALID_DEVICE_REQUEST; 653 654 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 655 "No queue configured for WDFDEVICE 0x%p, " 656 "failing WDFREQUEST 0x%p %!STATUS!", 657 Device->GetHandle(), 658 pRequest->GetObjectHandle(), 659 status); 660 661 FxVerifierDbgBreakPoint(FxDriverGlobals); 662 663 // 664 // Return it back to the driver to decide the outcome 665 // 666 goto Error; 667 } 668 } 669 670 // 671 // If the queue is a default-queue and driver is a filter then before 672 // calling the queue we should make sure the queue can dispatch 673 // requests to the driver. If the queue cannot dispatch request, 674 // we should forward it down to the lower driver ourself. 675 if (m_Filter && 676 pQueue == m_DefaultQueue && 677 pQueue->IsIoEventHandlerRegistered((WDF_REQUEST_TYPE)Irp->GetMajorFunction()) == FALSE) { 678 // 679 // Default queue doesn't have callback events registered to 680 // handle this request. So forward it down. 681 // 682 goto Forward; 683 } 684 685 pQueue->AddRef(); 686 687 // Must add a reference before releasing the callback and its reference 688 pRequest->ADDREF(FXREQUEST_STATE_TAG); 689 690 // Release the callback 691 oldState = pRequest->SetCompletionState(FxRequestCompletionStateNone); 692 ASSERT(oldState != FxRequestCompletionStateNone); 693 UNREFERENCED_PARAMETER(oldState); 694 695 status = pQueue->QueueRequestFromForward(pRequest); 696 697 pQueue->Release(); 698 699 // 700 // If not successfull, must place the request back 701 // to the state it was in on entry so that the driver 702 // can decide what to do next with it 703 // 704 if (!NT_SUCCESS(status)) { 705 706 // 707 // If the request comes back to us, it should still 708 // have a reference count of 1 709 // 710 oldState = pRequest->SetCompletionState(FxRequestCompletionStateIoPkg); 711 712 ASSERT(oldState == FxRequestCompletionStateNone); 713 UNREFERENCED_PARAMETER(oldState); 714 715 // 716 // Release the reference count on the request since 717 // the callback will hold the only one that gets 718 // decremented when the request is completed 719 // 720 pRequest->RELEASE(FXREQUEST_STATE_TAG); 721 goto Error; 722 } 723 else { 724 // 725 // On success, can not touch the request since it 726 // may have already been completed 727 // 728 } 729 730 return status; 731 732 Forward: 733 734 // 735 // Cannot send-and-forget a request with a formatted IO context. 736 // 737 if (pRequest->HasContext()) { 738 status = STATUS_INVALID_DEVICE_REQUEST; 739 740 DoTraceLevelMessage( 741 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 742 "Cannot send-and-forget WDFREQUEST 0x%p with formatted IO" 743 " context for filter WDFDEVICE 0x%p, %!STATUS!", 744 pRequest->GetObjectHandle(), 745 Device->GetHandle(), 746 status ); 747 748 FxVerifierDbgBreakPoint(FxDriverGlobals); 749 goto Error; 750 } 751 752 // 753 // This will skip the current stack location and perform 754 // early dispose on the request. 755 // 756 pRequest->PreProcessSendAndForget(); 757 758 (VOID)Irp->CallDriver(Device->GetAttachedDevice()); 759 760 // 761 // This will delete the request and free the memory back 762 // to the device lookaside list. 763 // 764 pRequest->PostProcessSendAndForget(); 765 766 // 767 // Return a success status in this code path even if the previous call 768 // to send the request to the lower driver failed. The status code returned 769 // by this function should reflect the status of enqueuing the request and 770 // not the status returned by the lower driver. 771 // 772 return STATUS_SUCCESS; 773 774 Error: 775 776 // 777 // If not successful, we must set the original verifier flags. 778 // 779 VerifyEnqueueRequestRestoreFlags(FxDriverGlobals, pRequest, origVerifierFlags); 780 781 return status; 782 } 783 784 _Must_inspect_result_ 785 NTSTATUS 786 FxPkgIo::ConfigureDynamicDispatching( 787 __in UCHAR MajorFunction, 788 __in_opt FxCxDeviceInfo* CxDeviceInfo, 789 __in PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDispatch, 790 __in_opt WDFCONTEXT DriverContext 791 ) 792 { 793 NTSTATUS status; 794 PFX_DRIVER_GLOBALS fxDriverGlobals; 795 PLIST_ENTRY next; 796 FxIrpDynamicDispatchInfo* dispatchInfo; 797 LONG mjIndex; 798 CCHAR driverIndex; 799 BOOLEAN addNew; 800 801 fxDriverGlobals = GetDriverGlobals(); 802 addNew = TRUE; 803 804 mjIndex = FxIrpDynamicDispatchInfo::Mj2Index(MajorFunction); 805 806 // 807 // Indirect MajorFunction validation. 808 // 809 if (mjIndex >= FxIrpDynamicDispatchInfo::DynamicDispatchMax) { 810 status = STATUS_INVALID_PARAMETER; 811 DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 812 "Invalid MajorFunction %!IRPMJ!, %!STATUS!", 813 MajorFunction, status); 814 goto Done; 815 } 816 817 // 818 // Get driver I/O device path index. 819 // 820 driverIndex = FxDevice::GetCxDriverIndex(CxDeviceInfo); 821 822 // 823 // Insert new info into correct slot in the I/O path. 824 // Index goes from higher to lower (..., 2, 1, 0) b/c cx's callback is called before 825 // client's one. 826 // 827 for (next = m_DynamicDispatchInfoListHead.Flink; 828 next != &m_DynamicDispatchInfoListHead; 829 next = next->Flink) { 830 831 CCHAR curIndex = 0; 832 833 dispatchInfo = CONTAINING_RECORD(next, 834 FxIrpDynamicDispatchInfo, 835 ListEntry); 836 // 837 // Get current I/O device path index. 838 // 839 curIndex = FxDevice::GetCxDriverIndex(dispatchInfo->CxDeviceInfo); 840 if (driverIndex == curIndex) { 841 // 842 // Found it. 843 // 844 if (dispatchInfo->Dispatch[mjIndex].EvtDeviceDynamicDispatch != NULL) { 845 status = STATUS_INVALID_PARAMETER; 846 DoTraceLevelMessage( 847 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 848 "Driver %p has already set a dispatch callback for " 849 "%!IRPMJ!, %!STATUS!", 850 CxDeviceInfo == NULL ? 851 GetDriver()->GetHandle() : 852 CxDeviceInfo->Driver->GetHandle(), 853 MajorFunction, status); 854 goto Done; 855 } 856 857 dispatchInfo->Dispatch[mjIndex].DriverContext = DriverContext; 858 dispatchInfo->Dispatch[mjIndex].EvtDeviceDynamicDispatch = 859 EvtDeviceWdmIrpDispatch; 860 861 ASSERT(dispatchInfo->CxDeviceInfo == CxDeviceInfo); 862 863 addNew = FALSE; 864 break; 865 } 866 else if (driverIndex > curIndex) { 867 // 868 // Not found (past valid range), add one before current. 869 // 870 break; 871 } 872 else if (driverIndex < curIndex) { 873 // 874 // Keep looking, too high. 875 // 876 continue; 877 } 878 } 879 880 if (addNew) { 881 dispatchInfo = new(fxDriverGlobals) FxIrpDynamicDispatchInfo(); 882 if (dispatchInfo == NULL) { 883 status = STATUS_INSUFFICIENT_RESOURCES; 884 DoTraceLevelMessage( 885 fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 886 "Couldn't create object DynamicDispatchInfo, %!STATUS!", 887 status); 888 goto Done; 889 } 890 891 dispatchInfo->CxDeviceInfo = CxDeviceInfo; 892 dispatchInfo->Dispatch[mjIndex].DriverContext = DriverContext; 893 dispatchInfo->Dispatch[mjIndex].EvtDeviceDynamicDispatch = 894 EvtDeviceWdmIrpDispatch; 895 896 // 897 // We must insert it before 'next' element. 898 // 899 InsertTailList(next, &dispatchInfo->ListEntry); 900 } 901 902 status = STATUS_SUCCESS; 903 904 Done: 905 return status; 906 } 907 908 _Must_inspect_result_ 909 NTSTATUS 910 FxPkgIo::ConfigureForwarding( 911 __inout FxIoQueue* TargetQueue, 912 __in WDF_REQUEST_TYPE RequestType 913 ) 914 { 915 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 916 KIRQL irql; 917 NTSTATUS status; 918 919 ASSERT(RequestType <= IRP_MJ_MAXIMUM_FUNCTION); 920 921 if(TargetQueue->IsIoEventHandlerRegistered(RequestType) == FALSE){ 922 status = STATUS_INVALID_DEVICE_REQUEST; 923 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 924 "Must have EvtIoDefault or %!WDF_REQUEST_TYPE! " 925 "specific dispatch event registered for " 926 "WDFQUEUE 0x%p, %!STATUS!", RequestType, 927 TargetQueue->GetObjectHandle(), 928 status); 929 FxVerifierDbgBreakPoint(FxDriverGlobals); 930 return status; 931 } 932 933 // Lock IoPackage data structure 934 935 Lock(&irql); 936 937 if (TargetQueue == m_DefaultQueue) { 938 status = STATUS_INVALID_DEVICE_REQUEST; 939 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 940 "Default WDFQUEUE 0x%p cannot be configured to " 941 "dispatch specific type of request, %!STATUS!", 942 TargetQueue->GetObjectHandle(), 943 status); 944 FxVerifierDbgBreakPoint(FxDriverGlobals); 945 Unlock(irql); 946 return status; 947 } 948 949 // Error if already has an entry 950 if (m_DispatchTable[RequestType] != NULL && 951 m_DispatchTable[RequestType] != m_DefaultQueue) { 952 status = STATUS_WDF_BUSY; 953 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 954 "%!WDF_REQUEST_TYPE! is already configured for" 955 "WDFQUEUE 0x%p, %!STATUS!", RequestType, 956 TargetQueue->GetObjectHandle(), 957 status); 958 FxVerifierDbgBreakPoint(FxDriverGlobals); 959 Unlock(irql); 960 return status; 961 } 962 963 // 964 // We don't take an extra reference count since we already 965 // have one from our associated list (DriverQueues) 966 // 967 m_DispatchTable[RequestType] = TargetQueue; 968 969 // 970 // Queues configured to auto-dispatch requests cannot be deleted 971 // 972 TargetQueue->MarkNoDeleteDDI(); 973 974 Unlock(irql); 975 976 return STATUS_SUCCESS; 977 } 978 979 _Must_inspect_result_ 980 NTSTATUS 981 FxPkgIo::CreateQueue( 982 __in PWDF_IO_QUEUE_CONFIG Config, 983 __in PWDF_OBJECT_ATTRIBUTES QueueAttributes, 984 __in_opt FxDriver* Caller, 985 __deref_out FxIoQueue** ppQueue 986 ) 987 { 988 PFX_DRIVER_GLOBALS pFxDriverGlobals; 989 FxObject* pParent; 990 FxIoQueue* pQueue; 991 NTSTATUS status; 992 FxDriver* pDriver; 993 994 pParent = NULL; 995 pQueue = NULL; 996 pDriver = NULL; 997 pFxDriverGlobals = GetDriverGlobals(); 998 999 if (QueueAttributes != NULL && QueueAttributes->ParentObject != NULL) { 1000 CfxDeviceBase* pSearchDevice; 1001 1002 FxObjectHandleGetPtr(pFxDriverGlobals, 1003 QueueAttributes->ParentObject, 1004 FX_TYPE_OBJECT, 1005 (PVOID*)&pParent); 1006 1007 pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL); 1008 1009 if (pSearchDevice == NULL) { 1010 status = STATUS_INVALID_DEVICE_REQUEST; 1011 1012 DoTraceLevelMessage( 1013 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1014 "QueueAttributes->ParentObject 0x%p must have WDFDEVICE as an " 1015 "eventual ancestor, %!STATUS!", 1016 QueueAttributes->ParentObject, status); 1017 1018 return status; 1019 } 1020 else if (pSearchDevice != m_DeviceBase) { 1021 status = STATUS_INVALID_DEVICE_REQUEST; 1022 1023 DoTraceLevelMessage( 1024 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1025 "Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but " 1026 "not the same WDFDEVICE 0x%p passed to WdfIoQueueCreate, " 1027 "%!STATUS!", 1028 QueueAttributes->ParentObject, pSearchDevice->GetHandle(), 1029 m_Device->GetHandle(), status); 1030 1031 return status; 1032 } 1033 } 1034 else { 1035 // 1036 // By default, use the package as the parent 1037 // 1038 pParent = this; 1039 } 1040 1041 // 1042 // v1.11 and up: get driver object if driver handle is specified. 1043 // Client driver can also specify a driver handle, the end result in this case is 1044 // a PkgIoContext that is NULL (see below), i.e., the same as if driver handle 1045 // was NULL. 1046 // 1047 if (Config->Size > sizeof(WDF_IO_QUEUE_CONFIG_V1_9) && 1048 Config->Driver != NULL) { 1049 1050 FxObjectHandleGetPtr(GetDriverGlobals(), 1051 Config->Driver, 1052 FX_TYPE_DRIVER, 1053 (PVOID*)&pDriver); 1054 } 1055 1056 status = FxIoQueue::_Create(pFxDriverGlobals, 1057 QueueAttributes, 1058 Config, 1059 Caller, 1060 this, 1061 m_PowerStateOn, 1062 &pQueue 1063 ); 1064 1065 if (!NT_SUCCESS(status)) { 1066 ASSERT(pQueue == NULL); 1067 return status; 1068 } 1069 1070 // 1071 // Class extension support: associate queue with a specific cx layer. 1072 // 1073 if (pDriver != NULL) { 1074 pQueue->SetCxDeviceInfo(m_Device->GetCxDeviceInfo(pDriver)); 1075 } 1076 1077 status = pQueue->Commit(QueueAttributes, NULL, pParent); 1078 if (!NT_SUCCESS(status)) { 1079 pQueue->DeleteFromFailedCreate(); 1080 return status; 1081 } 1082 1083 AddIoQueue(pQueue); 1084 *ppQueue = pQueue; 1085 1086 return status; 1087 } 1088 1089 1090 VOID 1091 FxPkgIo::RemoveQueueReferences( 1092 __inout FxIoQueue* pQueue 1093 ) 1094 /*++ 1095 1096 Routine Description: 1097 1098 This is called from FxIoQueue::Dispose to remove 1099 the queue from the transaction list. 1100 1101 Since this acquires the FxPkgIo lock, it assumes that 1102 no calls are made into FxIoQueue while holding the 1103 FxPkgIo lock. 1104 1105 Arguments: 1106 1107 None 1108 1109 Return Value: 1110 None 1111 --*/ 1112 { 1113 // Remove it from transacation list 1114 RemoveIoQueue(pQueue); 1115 return; 1116 } 1117 1118 _Must_inspect_result_ 1119 NTSTATUS 1120 FxPkgIo::SetFilter( 1121 __in BOOLEAN Value 1122 ) 1123 { 1124 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 1125 1126 if (m_DefaultQueue != NULL) { 1127 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1128 "I/O Package already has a default queue. " 1129 "SetFilter must be called before creating " 1130 "a default queue %!STATUS!", 1131 STATUS_INVALID_DEVICE_REQUEST); 1132 FxVerifierDbgBreakPoint(FxDriverGlobals); 1133 return STATUS_INVALID_DEVICE_REQUEST; 1134 } 1135 1136 m_Filter = Value; 1137 1138 return STATUS_SUCCESS; 1139 } 1140 1141 _Must_inspect_result_ 1142 NTSTATUS 1143 FxPkgIo::StopProcessingForPower( 1144 __in FxIoStopProcessingForPowerAction Action 1145 ) 1146 1147 /*++ 1148 1149 Routine Description: 1150 1151 Stops all PowerManaged queues automatic I/O processing due to 1152 a power event that requires I/O to stop. 1153 1154 This is called on a PASSIVE_LEVEL thread that can block until 1155 I/O has been stopped, or completed/cancelled. 1156 1157 Arguments: 1158 1159 Action - 1160 1161 FxIoStopProcessingForPowerHold: 1162 the function returns when the driver has acknowledged that it has 1163 stopped all I/O processing, but may have outstanding "in-flight" requests 1164 that have not been completed. 1165 1166 FxIoStopProcessingForPowerPurgeManaged: 1167 the function returns when all requests from a power managed queue have 1168 been completed and/or cancelled., and there are no more in-flight requests. 1169 1170 FxIoStopProcessingForPowerPurgeNonManaged: 1171 the function returns when all requests from a non-power managed queue have 1172 been completed and/or cancelled., and there are no more in-flight requests. 1173 Only called during device-remove. 1174 1175 Return Value: 1176 1177 NTSTATUS 1178 1179 --*/ 1180 1181 { 1182 KIRQL irql; 1183 FxIoQueue* queue; 1184 SINGLE_LIST_ENTRY queueList, *ple; 1185 1186 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, 1187 "Perform %!FxIoStopProcessingForPowerAction! for all queues of " 1188 "WDFDEVICE 0x%p", Action, m_Device->GetHandle()); 1189 1190 queueList.Next = NULL; 1191 1192 Lock(&irql); 1193 // 1194 // Device is moving into low power state. So any new queues 1195 // created after this point would start off as powered off. 1196 // 1197 m_PowerStateOn = FALSE; 1198 1199 // 1200 // If queues are shutting down, any new queue created after 1201 // this point would not accept any requests. 1202 // 1203 switch(Action) { 1204 case FxIoStopProcessingForPowerPurgeManaged: 1205 case FxIoStopProcessingForPowerPurgeNonManaged: 1206 m_QueuesAreShuttingDown = TRUE; 1207 break; 1208 } 1209 1210 GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOff); 1211 1212 Unlock(irql); 1213 1214 // 1215 // If the power action is hold then first change the state of all the queues 1216 // to PowerStartTransition. This will prevent the queues from dispatching 1217 // new requests before we start asking each queue to stop processing 1218 // inflight requests. 1219 // 1220 if(Action == FxIoStopProcessingForPowerHold) { 1221 1222 // 1223 // Walk the list without popping entries because we need to scan 1224 // the list again. 1225 // 1226 for(ple = queueList.Next; ple != NULL; ple = ple->Next) { 1227 1228 queue = FxIoQueue::_FromPowerSListEntry(ple); 1229 1230 queue->StartPowerTransitionOff(); 1231 } 1232 } 1233 1234 // 1235 // Ask the queues to stop processing inflight requests. 1236 // 1237 for (ple = PopEntryList(&queueList); ple != NULL; 1238 ple = PopEntryList(&queueList)) { 1239 1240 queue = FxIoQueue::_FromPowerSListEntry(ple); 1241 1242 queue->StopProcessingForPower(Action); 1243 1244 ple->Next = NULL; 1245 1246 queue->RELEASE(IO_ITERATOR_POWER_TAG); 1247 } 1248 1249 return STATUS_SUCCESS; 1250 } 1251 1252 _Must_inspect_result_ 1253 NTSTATUS 1254 FxPkgIo::ResumeProcessingForPower() 1255 1256 /*++ 1257 1258 Routine Description: 1259 1260 Resumes all PowerManaged queues for automatic I/O processing due to 1261 a power event that allows I/O to resume. 1262 1263 Non-PowerManaged queues are left alone. 1264 1265 Arguments: 1266 1267 Return Value: 1268 1269 NTSTATUS 1270 1271 --*/ 1272 1273 { 1274 KIRQL irql; 1275 FxIoQueue* queue; 1276 SINGLE_LIST_ENTRY queueList, *ple; 1277 1278 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, 1279 "Power resume all queues of WDFDEVICE 0x%p", 1280 m_Device->GetHandle()); 1281 1282 queueList.Next = NULL; 1283 1284 Lock(&irql); 1285 1286 GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOn); 1287 // 1288 // Change the state so that new queues created while we 1289 // are resuming the existing queues can be in a powered-on state. 1290 // 1291 m_PowerStateOn = TRUE; 1292 1293 // 1294 // Change the accepting state so that new queues created while we 1295 // are resuming the existing queues can be accept request. 1296 // 1297 m_QueuesAreShuttingDown = FALSE; 1298 1299 Unlock(irql); 1300 1301 // 1302 // We will power-up the queues in two steps. First we will resume 1303 // the power of all the queues and then we will start dispatching I/Os. 1304 // This is to avoid a queue being powered up at the begining of the list 1305 // trying to forward a request to another queue lower in the list that's 1306 // not powered up yet. 1307 // 1308 for(ple = queueList.Next; ple != NULL; ple = ple->Next) { 1309 1310 queue = FxIoQueue::_FromPowerSListEntry(ple); 1311 1312 queue->ResumeProcessingForPower(); 1313 } 1314 1315 for (ple = PopEntryList(&queueList); 1316 ple != NULL; 1317 ple = PopEntryList(&queueList)) { 1318 1319 queue = FxIoQueue::_FromPowerSListEntry(ple); 1320 1321 queue->StartPowerTransitionOn(); 1322 1323 ple->Next = NULL; 1324 1325 queue->RELEASE(IO_ITERATOR_POWER_TAG); 1326 } 1327 1328 return STATUS_SUCCESS; 1329 } 1330 1331 VOID 1332 FxPkgIo::ResetStateForRestart( 1333 VOID 1334 ) 1335 /*++ 1336 1337 Routine Description: 1338 This is called on a device which has been restarted from the removed 1339 state. It will reset purged queues so that they can accept new requests 1340 when ResumeProcessingForPower is called afterwards. 1341 1342 Arguments: 1343 None 1344 1345 Return Value: 1346 None 1347 1348 --*/ 1349 { 1350 KIRQL irql; 1351 FxIoQueue* queue; 1352 SINGLE_LIST_ENTRY queueList, *ple; 1353 1354 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIO, 1355 "Restart queues from purged state for WDFDEVICE 0x%p due to " 1356 "device restart", m_Device->GetHandle()); 1357 1358 queueList.Next = NULL; 1359 1360 Lock(&irql); 1361 1362 GetIoQueueListLocked(&queueList, FxIoQueueIteratorListPowerOn); 1363 1364 Unlock(irql); 1365 1366 for (ple = PopEntryList(&queueList); 1367 ple != NULL; 1368 ple = PopEntryList(&queueList)) { 1369 1370 queue = FxIoQueue::_FromPowerSListEntry(ple); 1371 1372 queue->ResetStateForRestart(); 1373 1374 ple->Next = NULL; 1375 1376 queue->RELEASE(IO_ITERATOR_POWER_TAG); 1377 } 1378 1379 Lock(&irql); 1380 1381 m_PowerStateOn = TRUE; 1382 1383 m_QueuesAreShuttingDown = FALSE; 1384 1385 Unlock(irql); 1386 1387 return; 1388 1389 } 1390 1391 _Must_inspect_result_ 1392 NTSTATUS 1393 FxPkgIo::FlushAllQueuesByFileObject( 1394 __in MdFileObject FileObject 1395 ) 1396 1397 /*++ 1398 1399 Routine Description: 1400 1401 Enumerate all the queues and cancel the requests that have 1402 the same fileobject as the Cleanup IRP. 1403 1404 We are making an assumption that cleanup irps are sent only 1405 at passive-level. 1406 1407 Return Value: 1408 1409 NTSTATUS 1410 1411 --*/ 1412 { 1413 FxIoQueue* queue = NULL; 1414 PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); 1415 FxIoQueueNode flushBookmark(FxIoQueueNodeTypeBookmark); 1416 KIRQL irql; 1417 1418 if(Mx::MxGetCurrentIrql() != PASSIVE_LEVEL) { 1419 1420 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, 1421 "Currently framework allow flushing of queues " 1422 "by fileobject on cleanup only at PASSIVE_LEVEL"); 1423 1424 FxVerifierDbgBreakPoint(pFxDriverGlobals); 1425 return STATUS_SUCCESS; 1426 } 1427 1428 // 1429 // Iterate through the queue list and flush each one. 1430 // 1431 Lock(&irql); 1432 queue = GetFirstIoQueueLocked(&flushBookmark, IO_ITERATOR_FLUSH_TAG); 1433 Unlock(irql); 1434 1435 while(queue != NULL) { 1436 1437 queue->FlushByFileObject(FileObject); 1438 1439 queue->RELEASE(IO_ITERATOR_FLUSH_TAG); 1440 1441 Lock(&irql); 1442 queue = GetNextIoQueueLocked(&flushBookmark, IO_ITERATOR_FLUSH_TAG); 1443 Unlock(irql); 1444 } 1445 1446 return STATUS_SUCCESS; 1447 } 1448 1449 static 1450 VOID 1451 GetIoQueueList_ProcessQueueListEntry( 1452 PLIST_ENTRY QueueLE, 1453 PSINGLE_LIST_ENTRY SListHead, 1454 PVOID Tag 1455 ) 1456 { 1457 FxIoQueueNode* listNode; 1458 FxIoQueue* queue; 1459 1460 // 1461 // Skip any nodes that are not queues. They can be bookmarks for 1462 // in-progress flush operations. 1463 // 1464 listNode = FxIoQueueNode::_FromListEntry(QueueLE); 1465 if (listNode->IsNodeType(FxIoQueueNodeTypeQueue) == FALSE) { 1466 return; 1467 } 1468 1469 queue = FxIoQueue::_FromIoPkgListEntry(QueueLE); 1470 PushEntryList(SListHead, &queue->m_PowerSListEntry); 1471 1472 // 1473 // Add a reference since the request will be touched outside of the 1474 // lock being held. We will use the enumerant value as the tag. 1475 // 1476 queue->ADDREF(Tag); 1477 } 1478 1479 VOID 1480 FxPkgIo::GetIoQueueListLocked( 1481 __in PSINGLE_LIST_ENTRY SListHead, 1482 __inout FxIoIteratorList ListType 1483 ) 1484 /*++ 1485 1486 Routine Description: 1487 1488 Called to make a temporary list of queues for iteration purpose. 1489 Function is called with the FxPkg lock held. 1490 1491 --*/ 1492 { 1493 PLIST_ENTRY listHead, le; 1494 1495 listHead = &m_IoQueueListHead; 1496 1497 if (FxIoQueueIteratorListPowerOn == ListType || 1498 (FxIoQueueIteratorListPowerOff == ListType && // backwards compatibility order. 1499 m_Device->IsCxInIoPath() == FALSE)) { 1500 // 1501 // Power up: first client driver's queues then cx's queues. 1502 // List is already sorted with client driver's queue first. 1503 // Since we are inserting into the head of the single list head, if we walked 1504 // over the list from first to last, we would reverse the entries. By walking 1505 // the list backwards, we build the single list head in the order of m_IoQueueListHead. 1506 // 1507 for (le = listHead->Blink; le != listHead; le = le->Blink) { 1508 GetIoQueueList_ProcessQueueListEntry(le, 1509 SListHead, 1510 IO_ITERATOR_POWER_TAG); 1511 } 1512 } 1513 else if (FxIoQueueIteratorListPowerOff == ListType) { 1514 // 1515 // Power down: first cx's queues then client driver's queues. 1516 // List is already sorted with client driver's queue first. 1517 // Since we are inserting into the head of the single list head, if we walked 1518 // over the list from last to first, we would reverse the entries. By walking 1519 // the list forwards, we build the single list head in the desired order 1520 // 1521 for (le = listHead->Flink; le != listHead; le = le->Flink) { 1522 GetIoQueueList_ProcessQueueListEntry(le, 1523 SListHead, 1524 IO_ITERATOR_POWER_TAG); 1525 } 1526 } 1527 else { 1528 ASSERT(FALSE); 1529 } 1530 } 1531 1532 VOID 1533 FxPkgIo::AddIoQueue( 1534 __inout FxIoQueue* IoQueue 1535 ) 1536 { 1537 PLIST_ENTRY listHead, le; 1538 FxIoQueue* queue; 1539 KIRQL irql; 1540 FxIoQueueNode* listNode; 1541 CCHAR queueIndex, curIndex; 1542 1543 listHead = &m_IoQueueListHead; 1544 queueIndex = FxDevice::GetCxDriverIndex(IoQueue->GetCxDeviceInfo()); 1545 Lock(&irql); 1546 1547 ASSERT(IoQueue->m_IoPkgListNode.IsNodeType(FxIoQueueNodeTypeQueue)); 1548 1549 // 1550 // Insert new queue in sorted list; search from last to first. 1551 // 1552 for (le = listHead->Blink; le != listHead; le = le->Blink) { 1553 // 1554 // Skip any nodes that are not queues. They can be bookmarks for 1555 // in-progress flush operations. 1556 // 1557 listNode = FxIoQueueNode::_FromListEntry(le); 1558 if (listNode->IsNodeType(FxIoQueueNodeTypeQueue) == FALSE) { 1559 continue; 1560 } 1561 1562 // 1563 // Get current queue's driver index. 1564 // 1565 queue = FxIoQueue::_FromIoPkgListEntry(le); 1566 curIndex = FxDevice::GetCxDriverIndex(queue->GetCxDeviceInfo()); 1567 // 1568 // Queues are inserted in order at the end of its allowed range. 1569 // 1570 if (curIndex < queueIndex || curIndex == queueIndex) { 1571 break; 1572 } 1573 } 1574 1575 InsertHeadList(le, &IoQueue->m_IoPkgListNode.m_ListEntry); 1576 1577 if (m_PowerStateOn) { 1578 IoQueue->SetPowerState(FxIoQueuePowerOn); 1579 } else { 1580 IoQueue->SetPowerState(FxIoQueuePowerOff); 1581 if (m_QueuesAreShuttingDown) { 1582 // Clear accept requests 1583 IoQueue->SetStateForShutdown(); 1584 } 1585 } 1586 1587 Unlock(irql); 1588 1589 return; 1590 } 1591 1592 VOID 1593 FxPkgIo::RemoveIoQueue( 1594 __inout FxIoQueue* IoQueue 1595 ) 1596 { 1597 KIRQL irql; 1598 1599 Lock(&irql); 1600 1601 RemoveEntryList(&IoQueue->m_IoPkgListNode.m_ListEntry); 1602 ASSERT(IoQueue->m_IoPkgListNode.IsNodeType(FxIoQueueNodeTypeQueue)); 1603 1604 InitializeListHead(&IoQueue->m_IoPkgListNode.m_ListEntry); 1605 1606 Unlock(irql); 1607 } 1608 1609 FxIoQueue* 1610 FxPkgIo::GetFirstIoQueueLocked( 1611 __in FxIoQueueNode* QueueBookmark, 1612 __in PVOID Tag 1613 ) 1614 /*++ 1615 1616 Routine Description: 1617 1618 Inserts the provided bookmark (FxIoQueueNode) at the beginning 1619 of the IO Package's queue list, and calls GetNextIoQueueLocked 1620 to retrieve the first queue and to advance the bookmark. 1621 1622 Function is called with the FxPkg lock held. 1623 1624 Return Value: 1625 1626 NULL if there are no queues in list else 1627 FxIoQueue* reference to first queue in list. 1628 1629 --*/ 1630 { 1631 ASSERT(QueueBookmark->IsNodeType(FxIoQueueNodeTypeBookmark)); 1632 ASSERT(IsListEmpty(&QueueBookmark->m_ListEntry)); 1633 1634 InsertHeadList(&m_IoQueueListHead, &QueueBookmark->m_ListEntry); 1635 1636 return GetNextIoQueueLocked(QueueBookmark, Tag); 1637 } 1638 1639 FxIoQueue* 1640 FxPkgIo::GetNextIoQueueLocked( 1641 __in FxIoQueueNode* QueueBookmark, 1642 __in PVOID Tag 1643 ) 1644 /*++ 1645 1646 Routine Description: 1647 1648 Moves the provided bookmark ahead in the IO Package's queue list 1649 and returns the next available queue (if any). 1650 1651 Return Value: 1652 1653 NULL if there are no more queues in list else 1654 FxIoQueue* reference to the next queue in list. 1655 1656 --*/ 1657 { 1658 PLIST_ENTRY ple = NULL; 1659 FxIoQueue* queue = NULL; 1660 FxIoQueueNode* listNode = NULL; 1661 1662 ASSERT(QueueBookmark->IsNodeType(FxIoQueueNodeTypeBookmark)); 1663 ASSERT(IsListEmpty(&QueueBookmark->m_ListEntry) == FALSE); 1664 1665 // 1666 // Try to advance bookmark to next location. 1667 // 1668 ple = QueueBookmark->m_ListEntry.Flink; 1669 RemoveEntryList(&QueueBookmark->m_ListEntry); 1670 InitializeListHead(&QueueBookmark->m_ListEntry); 1671 1672 for (; ple != &m_IoQueueListHead; ple = ple->Flink) { 1673 // 1674 // Skip any nodes that are not queues. These nodes can be 1675 // bookmarks for in-progress flush operations. 1676 // 1677 listNode = FxIoQueueNode::_FromListEntry(ple); 1678 if (listNode->IsNodeType(FxIoQueueNodeTypeQueue)) { 1679 1680 // 1681 // This entry is a real queue. 1682 // 1683 queue = FxIoQueue::_FromIoPkgListEntry(ple); 1684 queue->ADDREF(Tag); 1685 1686 // 1687 // Insert bookmark after this entry. 1688 // 1689 InsertHeadList(ple, &QueueBookmark->m_ListEntry); 1690 1691 break; 1692 } 1693 } 1694 1695 return queue; 1696 } 1697 1698 NTSTATUS 1699 FxPkgIo::DispathToInCallerContextCallback( 1700 __in FxIoInCallerContext *InCallerContextInfo, 1701 __in FxRequest *Request, 1702 __inout MdIrp Irp 1703 ) 1704 { 1705 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1706 FxRequestCompletionState oldState; 1707 FxIrp fxIrp(Irp); 1708 1709 pFxDriverGlobals = GetDriverGlobals(); 1710 1711 // 1712 // Mark the IRP pending since we are going 1713 // to return STATUS_PENDING regardless of whether 1714 // the driver completes the request right away 1715 // or not 1716 // 1717 fxIrp.MarkIrpPending(); 1718 1719 if (pFxDriverGlobals->FxVerifierOn) { 1720 Request->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT | 1721 FXREQUEST_FLAG_DRIVER_OWNED); 1722 } 1723 1724 // 1725 // Set a completion callback to manage the reference 1726 // count on the request 1727 // 1728 oldState = Request->SetCompletionState(FxRequestCompletionStateIoPkg); 1729 1730 ASSERT(oldState == FxRequestCompletionStateNone); 1731 UNREFERENCED_PARAMETER(oldState); 1732 1733 // 1734 // Release the reference count on the request since 1735 // the callback will hold the only one that gets 1736 // decremented when the request is completed 1737 // 1738 Request->RELEASE(FXREQUEST_STATE_TAG); 1739 1740 Request->SetPresented(); 1741 1742 // 1743 // Drivers that use this API are responsible for handling 1744 // all locking, threading, and IRQL level issues... 1745 // 1746 InCallerContextInfo->Invoke(m_Device->GetHandle(), 1747 Request->GetHandle()); 1748 // 1749 // The driver is responsible for calling WdfDeviceEnqueueRequest to insert 1750 // it back into the I/O processing pipeline, or completing it. 1751 // 1752 1753 return STATUS_PENDING; 1754 } 1755 1756 _Must_inspect_result_ 1757 NTSTATUS 1758 FxPkgIo::VerifierFreeRequestToTestForwardProgess( 1759 __in FxRequest* Request 1760 ) 1761 { 1762 BOOLEAN failAllocation; 1763 PFX_DRIVER_GLOBALS pFxDriverGlobals; 1764 1765 pFxDriverGlobals = GetDriverGlobals(); 1766 failAllocation = FALSE; 1767 // 1768 // forwardProgressTestFailAll takes precedence over forwardProgressTestFailRandom 1769 // 1770 if (IsFxVerifierTestForwardProgressFailAll(pFxDriverGlobals)) { 1771 failAllocation = TRUE; 1772 } 1773 else if (IsFxVerifierTestForwardProgressFailRandom(pFxDriverGlobals)) { 1774 // 1775 // Modulo 17 makes the probability of failure ~6% just like verifier.exe 1776 // 1777 failAllocation = (FxRandom(&m_RandomSeed) % 17 == 0); 1778 } 1779 1780 if (failAllocation) { 1781 // 1782 // Don't use DeleteObject() here as the Request wasn't presented to the 1783 // driver and the cleanup /dispose callback can be invoked unless 1784 // we use FreeRequest() which clears the cleanup /dispose callbacks 1785 // 1786 Request->FreeRequest(); 1787 1788 return STATUS_INSUFFICIENT_RESOURCES; 1789 } 1790 else { 1791 return STATUS_SUCCESS; 1792 } 1793 } 1794 1795 1796