1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxDriver.cpp 8 9 Abstract: 10 11 This is the main driver framework. 12 13 Author: 14 15 16 17 Environment: 18 19 Both kernel and user mode 20 21 Revision History: 22 23 --*/ 24 25 #include "coreprivshared.hpp" 26 #include "fxiotarget.hpp" 27 28 // Tracing support 29 extern "C" { 30 // #include "FxDriver.tmh" 31 } 32 33 FxDriver::FxDriver( 34 __in MdDriverObject ArgDriverObject, 35 __in PWDF_DRIVER_CONFIG DriverConfig, 36 __in PFX_DRIVER_GLOBALS FxDriverGlobals 37 ) : 38 FxNonPagedObject(FX_TYPE_DRIVER, sizeof(FxDriver), FxDriverGlobals), 39 m_DriverObject(ArgDriverObject), 40 m_CallbackMutexLock(FxDriverGlobals) 41 { 42 RtlInitUnicodeString(&m_RegistryPath, NULL); 43 44 45 46 47 48 49 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 50 m_ExecutionLevel = WdfExecutionLevelDispatch; 51 #else 52 m_ExecutionLevel = WdfExecutionLevelPassive; 53 #endif 54 55 m_SynchronizationScope = WdfSynchronizationScopeNone; 56 57 m_CallbackLockPtr = NULL; 58 m_CallbackLockObjectPtr = NULL; 59 60 m_DisposeList = NULL; 61 62 // 63 // These are initialized up front so that sub objects 64 // can have the right configuration 65 // 66 WDF_DRIVER_CONFIG_INIT(&m_Config, NULL); 67 68 // Only copy the smallest of what is specified and our size 69 RtlCopyMemory(&m_Config, DriverConfig, min(sizeof(m_Config), DriverConfig->Size) ); 70 71 m_DebuggerConnected = FALSE; 72 73 #if FX_IS_USER_MODE 74 m_DriverParametersKey = NULL; 75 #endif 76 } 77 78 FxDriver::~FxDriver() 79 { 80 // Make it always present right now even on free builds 81 if (IsDisposed() == FALSE) { 82 DoTraceLevelMessage( 83 GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGDRIVER, 84 "FxDriver 0x%p not disposed: this maybe a driver reference count " 85 "problem with WDFDRIVER 0x%p", this, GetObjectHandleUnchecked()); 86 87 FxVerifierBugCheck(GetDriverGlobals(), 88 WDF_OBJECT_ERROR, 89 (ULONG_PTR) GetObjectHandleUnchecked(), 90 (ULONG_PTR) this); 91 } 92 93 // 94 // Free the memory for the registry path if required. 95 // 96 if (m_RegistryPath.Buffer) { 97 FxPoolFree(m_RegistryPath.Buffer); 98 } 99 100 if (m_DisposeList != NULL) { 101 m_DisposeList->DeleteObject(); 102 } 103 104 #if FX_IS_USER_MODE 105 // 106 // Close the R/W handle to the driver's service parameters key 107 // that we opened during Initialize. 108 // 109 if (m_DriverParametersKey != NULL) { 110 NTSTATUS status = FxRegKey::_Close(m_DriverParametersKey); 111 if (!NT_SUCCESS(status)) { 112 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDRIVER, 113 "Cannot close Driver Parameters key %!STATUS!", 114 status); 115 } 116 m_DriverParametersKey = NULL; 117 } 118 119 // 120 // The host-created driver object holds a reference to this 121 // FxDriver object. Clear it, since this object was deleted. 122 // 123 ClearDriverObjectFxDriver(); 124 #endif 125 } 126 127 BOOLEAN 128 FxDriver::Dispose( 129 VOID 130 ) 131 { 132 if (m_DisposeList != NULL) { 133 m_DisposeList->WaitForEmpty(); 134 } 135 136 return FxNonPagedObject::Dispose(); // __super call 137 } 138 139 VOID 140 FxDriver::Unload( 141 __in MdDriverObject DriverObject 142 ) 143 { 144 PFX_DRIVER_GLOBALS pFxDriverGlobals; 145 FxDriver *pDriver; 146 147 pDriver = FxDriver::GetFxDriver(DriverObject); 148 if (pDriver == NULL) { 149 return; 150 } 151 152 pFxDriverGlobals = pDriver->GetDriverGlobals(); 153 154 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, 155 "Unloading WDFDRIVER %p, PDRIVER_OBJECT_UM %p", 156 pDriver->GetHandle(), DriverObject); 157 // 158 // Invoke the driver if they specified an unload routine. 159 // 160 if (pDriver->m_DriverUnload.Method) { 161 pDriver->m_DriverUnload.Invoke(pDriver->GetHandle()); 162 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, 163 "Driver unload routine Exit WDFDRIVER %p, PDRIVER_OBJECT_UM %p", 164 pDriver->GetHandle(), DriverObject); 165 } 166 167 // 168 // Delete the FxDriver object. 169 // 170 // This releases the FxDriver reference. Must be called at PASSIVE 171 // 172 pDriver->DeleteObject(); 173 174 pFxDriverGlobals->Driver = NULL; 175 176 FxDestroy(pFxDriverGlobals); 177 } 178 179 VOID 180 FxDriver::_InitializeDriverName( 181 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 182 __in PCUNICODE_STRING RegistryPath 183 ) 184 /*++ 185 186 Routine Description: 187 Create a CHAR version of the service name contained in RegistryPath. 188 189 Arguments: 190 RegistryPath - the path to the service name in the registry. 191 192 Return Value: 193 None 194 195 --*/ 196 { 197 PWCHAR pCur, pBegin, pEnd; 198 199 RtlZeroMemory(&FxDriverGlobals->Public.DriverName[0], 200 sizeof(FxDriverGlobals->Public.DriverName) ); 201 202 if (RegistryPath == NULL) { 203 return; 204 } 205 206 pBegin = RegistryPath->Buffer; 207 208 // 209 // pEnd is one past the end of the string, while pCur is a pointer to the 210 // last character of the string. We will decrement pCur down towards the 211 // beginning of the string. 212 // 213 pEnd = pBegin + (RegistryPath->Length / sizeof(WCHAR)); 214 pCur = pEnd - 1; 215 216 for ( ; *pCur != L'\\' && pCur != pBegin; pCur--) { 217 DO_NOTHING(); 218 } 219 220 if (pCur != pBegin && *pCur == L'\\') { 221 size_t regLen; 222 ULONG i; 223 224 pCur++; 225 226 // 227 // Can't use wcslen becuase this is a UNICODE_STRING which means that it 228 // does not necessarily have a terminating NULL in the buffer. 229 // 230 regLen = pEnd - pCur; 231 if (regLen > WDF_DRIVER_GLOBALS_NAME_LEN-1) { 232 regLen = WDF_DRIVER_GLOBALS_NAME_LEN-1; 233 } 234 235 236 for (i = 0; i < regLen; i++) { 237 FxDriverGlobals->Public.DriverName[i] = (CHAR) pCur[i]; 238 } 239 } 240 else { 241 NTSTATUS status; 242 243 #if FX_CORE_MODE==FX_CORE_KERNEL_MODE 244 status = RtlStringCbCopyA(FxDriverGlobals->Public.DriverName, 245 sizeof(FxDriverGlobals->Public.DriverName), 246 "WDF"); 247 #else // USER_MODE 248 HRESULT hr; 249 hr = StringCbCopyA(FxDriverGlobals->Public.DriverName, 250 sizeof(FxDriverGlobals->Public.DriverName), 251 "WDF"); 252 if (HRESULT_FACILITY(hr) == FACILITY_WIN32) { 253 status = WinErrorToNtStatus(HRESULT_CODE(hr)); 254 } 255 else { 256 status = SUCCEEDED(hr) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; 257 } 258 #endif 259 260 UNREFERENCED_PARAMETER(status); 261 ASSERT(NT_SUCCESS(status)); 262 } 263 } 264 265 VOID 266 FxDriver::_InitializeTag( 267 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 268 __in PWDF_DRIVER_CONFIG Config 269 ) 270 /*++ 271 272 Routine Description: 273 Tries to create a tag for the driver based off of its name. This tag is 274 used for allocations made on behalf of the driver so that it is easier to 275 track which allocations belong to which image. 276 277 Arguments: 278 Config - driver writer provided config. in the future, may contain a tag 279 value in it 280 281 Return Value: 282 None 283 284 --*/ 285 { 286 PCHAR pBegin; 287 size_t length; 288 289 UNREFERENCED_PARAMETER(Config); 290 291 length = strlen(FxDriverGlobals->Public.DriverName); 292 pBegin = &FxDriverGlobals->Public.DriverName[0]; 293 294 if (length >= 3) { 295 // 296 // If the driver name begins with "WDF" (case insensitive), start after 297 // "WDF" 298 // 299 if ((pBegin[0] == 'w' || pBegin[0] == 'W') && 300 (pBegin[1] == 'd' || pBegin[1] == 'D') && 301 (pBegin[2] == 'f' || pBegin[2] == 'F')) { 302 length -=3; 303 pBegin += 3; 304 } 305 } 306 307 if (length <= 2) { 308 // 309 // 2 or less characters is not a unique enough tag, just use the default 310 // tag. 311 // 312 FxDriverGlobals->Tag = FX_TAG; 313 } 314 else { 315 316 if (length > sizeof(ULONG)) { 317 length = sizeof(ULONG); 318 } 319 320 // 321 // This copies the bytes in the right order (so that they appear correct 322 // when dumped as a sequence of chars) 323 // 324 RtlCopyMemory(&FxDriverGlobals->Tag, 325 pBegin, 326 length); 327 328 FxDriverGlobals->Public.DriverTag = FxDriverGlobals->Tag; 329 } 330 } 331 332 _Must_inspect_result_ 333 NTSTATUS 334 FxDriver::Initialize( 335 __in PCUNICODE_STRING ArgRegistryPath, 336 __in PWDF_DRIVER_CONFIG Config, 337 __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes 338 ) 339 { 340 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 341 NTSTATUS status; 342 343 // WDFDRIVER can not be deleted by the device driver 344 MarkNoDeleteDDI(); 345 346 MarkDisposeOverride(ObjectDoNotLock); 347 348 // 349 // Configure Constraints 350 // 351 ConfigureConstraints(DriverAttributes); 352 353 if (m_DriverObject.GetObject() == NULL) { 354 return STATUS_UNSUCCESSFUL; 355 } 356 357 // Allocate FxDisposeList 358 status = FxDisposeList::_Create(FxDriverGlobals, m_DriverObject.GetObject(), &m_DisposeList); 359 if (!NT_SUCCESS(status)) { 360 return status; 361 } 362 363 // 364 // Store FxDriver in Driver object extension 365 // 366 status = AllocateDriverObjectExtensionAndStoreFxDriver(); 367 if (!NT_SUCCESS(status)) { 368 return status; 369 } 370 371 // 372 // Store away the callback functions. 373 // 374 if ((Config->DriverInitFlags & WdfDriverInitNoDispatchOverride) == 0) { 375 // 376 // Caller doesn't want to override the dispatch table. That 377 // means that they want to create everything and still be in 378 // control (or at least the port driver will take over) 379 // 380 m_DriverDeviceAdd.Method = Config->EvtDriverDeviceAdd; 381 m_DriverUnload.Method = Config->EvtDriverUnload; 382 } 383 384 if (ArgRegistryPath != NULL) { 385 USHORT length; 386 387 length = ArgRegistryPath->Length + sizeof(UNICODE_NULL); 388 389 m_RegistryPath.Length = ArgRegistryPath->Length; 390 m_RegistryPath.MaximumLength = length; 391 m_RegistryPath.Buffer = (PWSTR) FxPoolAllocate( 392 GetDriverGlobals(), PagedPool, length); 393 394 if (m_RegistryPath.Buffer != NULL) { 395 RtlCopyMemory(m_RegistryPath.Buffer, 396 ArgRegistryPath->Buffer, 397 ArgRegistryPath->Length); 398 399 // 400 // other parts of WDF assumes m_RegistryPath.Buffer is 401 // a null terminated string. make sure it is. 402 // 403 m_RegistryPath.Buffer[length/sizeof(WCHAR)- 1] = UNICODE_NULL; 404 } 405 else { 406 // 407 // We failed to allocate space for the registry path 408 // so set the length to 0. 409 // 410 m_RegistryPath.Length = 0; 411 m_RegistryPath.MaximumLength = 0; 412 413 status = STATUS_INSUFFICIENT_RESOURCES; 414 } 415 } 416 417 if (NT_SUCCESS(status)) { 418 if ((Config->DriverInitFlags & WdfDriverInitNoDispatchOverride) == 0) { 419 UCHAR i; 420 421 // 422 // Set up dispatch routines. 423 // 424 if (Config->DriverInitFlags & WdfDriverInitNonPnpDriver) { 425 // 426 // NT4 style drivers must clear the AddDevice field in the 427 // driver object so that they can be unloaded while still 428 // having device objects around. 429 // 430 // If AddDevice is set, NT considers the driver a pnp driver 431 // and will not allow net stop to unload the driver. 432 // 433 m_DriverObject.SetDriverExtensionAddDevice(NULL); 434 435 // 436 // Unload for an NT4 driver is still optional if the driver 437 // does not want to be stopped (through net stop for 438 // instance). 439 // 440 if (Config->EvtDriverUnload != NULL) { 441 m_DriverObject.SetDriverUnload(Unload); 442 } 443 else { 444 m_DriverObject.SetDriverUnload(NULL); 445 } 446 447 } 448 else { 449 // 450 // PnP driver, set our routines up 451 // 452 m_DriverObject.SetDriverExtensionAddDevice(AddDevice); 453 m_DriverObject.SetDriverUnload(Unload); 454 } 455 456 // 457 // For any major control code that we use a remove lock, the 458 // following locations must be updated: 459 // 460 // 1) FxDevice::_RequiresRemLock() which decides if the remlock 461 // is required 462 // 2) FxDefaultIrpHandler::Dispatch might need to be changed if 463 // there is catchall generic post processing that must be done 464 // 3) Whereever the major code irp handler completes the irp or 465 // sends it down the stack. A good design would have all 466 // spots in the irp handler where this is done to call a 467 // common function. 468 // 469 WDFCASSERT(IRP_MN_REMOVE_DEVICE != 0x0); 470 471 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) 472 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { 473 if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) { 474 m_DriverObject.SetMajorFunction(i, FxDevice::Dispatch); 475 } 476 else { 477 m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLock); 478 } 479 } 480 #else // USER_MODE 481 for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { 482 if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) { 483 m_DriverObject.SetMajorFunction(i, FxDevice::DispatchUm); 484 } 485 else { 486 m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLockUm); 487 } 488 } 489 #endif 490 } 491 492 // 493 // Determine if the debugger is connected. 494 // 495 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) 496 if (KD_DEBUGGER_ENABLED == TRUE && KD_DEBUGGER_NOT_PRESENT == FALSE) { 497 m_DebuggerConnected = TRUE; 498 } 499 #endif 500 501 // 502 // Log this notable event after tracing has been initialized. 503 // 504 505 506 507 508 509 510 if ((Config->DriverInitFlags & WdfDriverInitNonPnpDriver) && 511 Config->EvtDriverUnload == NULL) { 512 513 DoTraceLevelMessage( 514 FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, 515 "Driver Object %p, reg path %wZ cannot be " 516 "unloaded, no DriverUnload routine specified", 517 m_DriverObject.GetObject(), &m_RegistryPath); 518 } 519 520 #if FX_IS_USER_MODE 521 // 522 // Open a R/W handle to the driver's service parameters key 523 // 524 status = OpenParametersKey(); 525 if (!NT_SUCCESS(status)) { 526 DoTraceLevelMessage( 527 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, 528 "Cannot open Driver Parameters key %!STATUS!", 529 status); 530 } 531 #endif 532 } 533 534 return status; 535 } 536 537 _Must_inspect_result_ 538 FxString * 539 FxDriver::GetRegistryPath( 540 VOID 541 ) 542 { 543 FxString *pString; 544 545 pString = new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) 546 FxString(GetDriverGlobals()); 547 548 if (pString != NULL) { 549 NTSTATUS status; 550 551 status = pString->Assign(m_RegistryPath.Buffer); 552 553 if (!NT_SUCCESS(status)) { 554 pString->Release(); 555 pString = NULL; 556 } 557 } 558 559 return pString; 560 } 561 562 563 VOID 564 FxDriver::ConfigureConstraints( 565 __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes 566 ) 567 /*++ 568 569 Routine Description: 570 571 Determine the pointer to the proper lock to acquire 572 for event callbacks from the FxDriver to the device driver 573 depending on the configured locking model. 574 575 Arguments: 576 DriverAttributes - caller supplied scope and level, used only if they 577 are not InheritFromParent. 578 579 Returns: 580 None 581 582 --*/ 583 { 584 BOOLEAN automaticLockingRequired; 585 586 automaticLockingRequired = FALSE; 587 588 // Initialize the mutex lock 589 m_CallbackMutexLock.Initialize(this); 590 591 592 593 594 595 596 597 598 599 MarkPassiveCallbacks(ObjectDoNotLock); 600 601 m_CallbackLockPtr = &m_CallbackMutexLock; 602 m_CallbackLockObjectPtr = this; 603 604 // 605 // Use the caller supplied scope and level only if they are not 606 // InheritFromParent. 607 // 608 if (DriverAttributes != NULL) { 609 610 if (DriverAttributes->ExecutionLevel != 611 WdfExecutionLevelInheritFromParent) { 612 m_ExecutionLevel = DriverAttributes->ExecutionLevel; 613 } 614 615 if (DriverAttributes->SynchronizationScope != 616 WdfSynchronizationScopeInheritFromParent) { 617 m_SynchronizationScope = DriverAttributes->SynchronizationScope; 618 } 619 } 620 621 // 622 // If the driver asks for any synchronization, we synchronize the 623 // WDFDRIVER object's own callbacks as well. 624 // 625 // (No option to extend synchronization for regular operations 626 // across all WDFDEVICE objects) 627 // 628 if (m_SynchronizationScope == WdfSynchronizationScopeDevice || 629 m_SynchronizationScope == WdfSynchronizationScopeQueue) { 630 631 automaticLockingRequired = TRUE; 632 } 633 634 // 635 // No FxDriver events are delivered from a thread that is 636 // not already at PASSIVE_LEVEL, so we don't need to 637 // allocate an FxSystemWorkItem if the execution level 638 // constraint is WdfExecutionLevelPassive. 639 // 640 // If any events are added FxDriver that could occur on a thread 641 // that is above PASSIVE_LEVEL, then an FxSystemWorkItem would 642 // need to be allocated to deliver those events similar to the 643 // code in FxIoQueue. 644 // 645 646 // 647 // Configure FxDriver event callback locks 648 // 649 if (automaticLockingRequired) { 650 m_DriverDeviceAdd.SetCallbackLockPtr(m_CallbackLockPtr); 651 } 652 else { 653 m_DriverDeviceAdd.SetCallbackLockPtr(NULL); 654 } 655 } 656 657