1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxVerifierLock.hpp 8 9 Abstract: 10 11 This is the C++ header for the verifier FxLock 12 13 This separate object allows the verifier overhead 14 to only be allocated when WdfVerifierLock is on. 15 16 Author: 17 18 19 20 Revision History: 21 22 23 Made it mode agnostic 24 25 New failure paths: 26 m_Mutex/m_Lock initialize 27 To enforce initialization hidden constructors 28 Callers are forced to use CreateAndInitialize methods 29 30 --*/ 31 32 #ifndef _FXVERIFIERLOCK_HPP_ 33 #define _FXVERIFIERLOCK_HPP_ 34 35 extern "C" { 36 #if defined(EVENT_TRACING) 37 #include "FxVerifierLock.hpp.tmh" 38 #endif 39 } 40 41 /** 42 * These define the lock order used by verifier 43 * for basic objects internal to the driver frameworks. 44 * 45 * Higher numbers are "lower" locks in the hierachy, which means 46 * a lock can be acquired if its number greater than or equal 47 * to the current one. 48 * 49 * Correct Order: 50 * 51 * FX_LOCK_ORDER_DRIVER -> FX_LOCK_ORDER_QUEUE -> FX_LOCK_ORDER_REQUEST 52 * 53 * Incorrect Order: 54 * 55 * FX_LOCK_ORDER_DRIVER -> FX_LOCK_ORDER_QUEUE -> FX_LOCK_ORDER_DEVICE 56 * 57 * FX_LOCK_ORDER_UNKNOWN represents an object who has not (yet) 58 * defined a lock order. It has the highest number, meaning it 59 * can be acquired holding any other locks, including itself. 60 * At some point in time, this will cause a verifier break point, 61 * otherwise we can not fully test the frameworks. 62 * 63 * FX_LOCK_ORDER_NONE is a statement by the object that it will 64 * not use its Lock/Unlock routines. Use of locks on this object 65 * under verifier will cause a verifier breakpoint. 66 * 67 * There is a table mapping these from FX_TYPE_* to the lock orders 68 * define here in fx\core\FxVerifierLock.cpp 69 * 70 */ 71 72 // 73 // These locks are driver frameworks "internal" object 74 // locks and are not intended to be held across callbacks 75 // to the driver. 76 // 77 // They are acquired and released as the result of driver 78 // calls into the frameworks, which may be holding a driver 79 // callback lock. 80 // 81 #define FX_LOCK_ORDER_NONE 0x0000 82 #define FX_LOCK_ORDER_UNKNOWN 0xFFFF 83 84 #define FX_LOCK_ORDER_PACKAGE_PDO 0x1000 85 #define FX_LOCK_ORDER_PACKAGE_FDO 0x1000 86 #define FX_LOCK_ORDER_WMI_IRP_HANDLER 0x1000 87 #define FX_LOCK_ORDER_PACKAGE_GENERAL 0x1000 88 89 #define FX_LOCK_ORDER_IO_TARGET 0x1000 90 91 #define FX_LOCK_ORDER_WMI_PROVIDER 0x1001 92 #define FX_LOCK_ORDER_WMI_INSTANCE 0x1002 93 94 #define FX_LOCK_ORDER_DMA_ENABLER 0x1000 95 #define FX_LOCK_ORDER_DMA_TRANSACTION 0x1001 96 #define FX_LOCK_ORDER_COMMON_BUFFER 0x1001 97 98 // 99 // A USB device owns a bunch of pipes, so make sure that device can acquire a 100 // pipe lock while locked, but not vice versa 101 // 102 #define FX_LOCK_ORDER_USB_DEVICE_IO_TARGET 0x1000 103 #define FX_LOCK_ORDER_USB_PIPE_IO_TARGET 0x1001 104 105 106 #define FX_LOCK_ORDER_DRIVER 0x1010 107 #define FX_LOCK_ORDER_DEVICE 0x1020 108 #define FX_LOCK_ORDER_MP_DEVICE 0x1020 109 #define FX_LOCK_ORDER_DEFAULT_IRP_HANDLER 0x1030 110 #define FX_LOCK_ORDER_QUEUE 0x1030 111 #define FX_LOCK_ORDER_PACKAGE_IO 0x1031 112 #define FX_LOCK_ORDER_REQUEST 0x1040 113 #define FX_LOCK_ORDER_IRPQUEUE 0x1051 114 #define FX_LOCK_ORDER_TIMER 0x1059 115 #define FX_LOCK_ORDER_DPC 0x1060 116 #define FX_LOCK_ORDER_WORKITEM 0x1060 117 #define FX_LOCK_ORDER_CLEANUPLIST 0x1060 118 #define FX_LOCK_ORDER_INTERRUPT 0x1060 119 #define FX_LOCK_ORDER_FILEOBJECT 0x1060 120 #define FX_LOCK_ORDER_DEVICE_LIST 0x1061 121 #define FX_LOCK_ORDER_COLLECTION 0x1070 // collection can be used in any 122 // of the above object's callbacks 123 #define FX_LOCK_ORDER_USEROBJECT 0x2000 124 125 // dispose list is very far down in the list because pretty much any item can 126 // be added to the dispose list while that object's lock is being held 127 #define FX_LOCK_ORDER_DISPOSELIST 0x8000 128 129 #define FX_LOCK_ORDER_SYSTEMWORKITEM FX_LOCK_ORDER_UNKNOWN 130 #define FX_LOCK_ORDER_SYSTEMTHREAD FX_LOCK_ORDER_UNKNOWN // No lock level 131 132 // 133 // These are the device driver callback locks 134 // used to synchronize callback to the device 135 // driver. They are "higher" than the internal 136 // frameworks locks since an internal frameworks lock 137 // should not be held when these are acquired. 138 // 139 // (which should only be due to FxCallback.Invoke to a driver 140 // event handler) 141 // 142 // This means they must have a lower number than the internal frameworks 143 // locks. 144 // 145 // They may be held when a device driver is calling into a frameworks 146 // DDI while in an event callback handler. 147 // 148 // These levels enforce not only the level of locks acquired 149 // and released by and for the driver, but also the rules 150 // about holding internal frameworks locks when calling into 151 // a driver. If a frameworks bug is holding a frameworks lock 152 // when it goes to do a callback, the attempt to acquire the 153 // lower numbered lock will raise the error. 154 // 155 #define FX_CALLBACKLOCK_ORDER_DRIVER 0x10 156 #define FX_CALLBACKLOCK_ORDER_DEVICE 0x20 157 #define FX_CALLBACKLOCK_ORDER_PACKAGE 0x30 158 #define FX_CALLBACKLOCK_ORDER_QUEUE 0x31 159 160 #define FX_VERIFIER_LOCK_ENTRY(FX_OBJECT_TYPE, FX_LOCK_ORDER) { FX_OBJECT_TYPE, FX_LOCK_ORDER } 161 162 // Internal FxLock spinlock entries 163 #define FX_VERIFIER_LOCK_ENTRIES() \ 164 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DRIVER, FX_LOCK_ORDER_DRIVER), \ 165 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEVICE, FX_LOCK_ORDER_DEVICE), \ 166 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_MP_DEVICE, FX_LOCK_ORDER_MP_DEVICE), \ 167 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_IO, FX_LOCK_ORDER_PACKAGE_IO), \ 168 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_INSTANCE, FX_LOCK_ORDER_WMI_INSTANCE), \ 169 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_PROVIDER, FX_LOCK_ORDER_WMI_PROVIDER), \ 170 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_QUEUE, FX_LOCK_ORDER_QUEUE), \ 171 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_REQUEST, FX_LOCK_ORDER_REQUEST), \ 172 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IRPQUEUE, FX_LOCK_ORDER_IRPQUEUE), \ 173 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_PDO, FX_LOCK_ORDER_PACKAGE_PDO), \ 174 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_FDO, FX_LOCK_ORDER_PACKAGE_FDO), \ 175 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_IRP_HANDLER, FX_LOCK_ORDER_WMI_IRP_HANDLER), \ 176 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_GENERAL, FX_LOCK_ORDER_PACKAGE_GENERAL), \ 177 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DMA_ENABLER, FX_LOCK_ORDER_DMA_ENABLER), \ 178 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DMA_TRANSACTION, FX_LOCK_ORDER_DMA_TRANSACTION), \ 179 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_COMMON_BUFFER, FX_LOCK_ORDER_COMMON_BUFFER), \ 180 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET, FX_LOCK_ORDER_IO_TARGET), \ 181 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_SELF, FX_LOCK_ORDER_IO_TARGET), \ 182 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_USB_DEVICE,FX_LOCK_ORDER_USB_DEVICE_IO_TARGET),\ 183 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_USB_PIPE, FX_LOCK_ORDER_USB_PIPE_IO_TARGET), \ 184 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DPC, FX_LOCK_ORDER_DPC), \ 185 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WORKITEM, FX_LOCK_ORDER_WORKITEM), \ 186 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_SYSTEMTHREAD, FX_LOCK_ORDER_SYSTEMTHREAD), \ 187 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_CLEANUPLIST, FX_LOCK_ORDER_CLEANUPLIST), \ 188 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_INTERRUPT, FX_LOCK_ORDER_INTERRUPT), \ 189 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_TIMER, FX_LOCK_ORDER_TIMER), \ 190 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_FILEOBJECT, FX_LOCK_ORDER_FILEOBJECT), \ 191 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_CHILD_LIST, FX_LOCK_ORDER_DEVICE_LIST), \ 192 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_SYSTEMWORKITEM, FX_LOCK_ORDER_SYSTEMWORKITEM), \ 193 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEFAULT_IRP_HANDLER, FX_LOCK_ORDER_DEFAULT_IRP_HANDLER), \ 194 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_COLLECTION, FX_LOCK_ORDER_COLLECTION), \ 195 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DISPOSELIST, FX_LOCK_ORDER_DISPOSELIST), \ 196 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_USEROBJECT, FX_LOCK_ORDER_USEROBJECT), \ 197 FX_VERIFIER_LOCK_ENTRY(0, 0) 198 199 // Device Driver Callback lock entries 200 #define FX_VERIFIER_CALLBACKLOCK_ENTRIES() \ 201 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DRIVER, FX_CALLBACKLOCK_ORDER_DRIVER), \ 202 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEVICE, FX_CALLBACKLOCK_ORDER_DEVICE), \ 203 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_IO, FX_CALLBACKLOCK_ORDER_PACKAGE), \ 204 FX_VERIFIER_LOCK_ENTRY(FX_TYPE_QUEUE, FX_CALLBACKLOCK_ORDER_QUEUE), \ 205 FX_VERIFIER_LOCK_ENTRY(0, 0) 206 207 // 208 // Mapping table structure between Fx object types and lock orders 209 // 210 struct FxVerifierOrderMapping { 211 USHORT ObjectType; 212 USHORT ObjectLockOrder; 213 }; 214 215 typedef struct FxVerifierOrderMapping *pFxVerifierOrderMapping; 216 // 217 // This must be a power of two for hash algorithm 218 // 219 // Table size is dependent on the number of active threads 220 // in the frameworks at a given time. This can not execeed 221 // the number of (virtual due to hyperthreading) CPU's in the system. 222 // 223 // Setting this number lower just increases collisions, but does 224 // not impede correct function. 225 // 226 #define VERIFIER_THREAD_HASHTABLE_SIZE 64 227 228 229 // 230 // This structure is used by verifier hash table implementation 231 // for linking records per thread 232 // 233 struct FxVerifierThreadTableEntry { 234 MxThread Thread; 235 FxVerifierLock* PerThreadPassiveLockList; 236 FxVerifierLock* PerThreadDispatchLockList; 237 LIST_ENTRY HashChain; 238 }; 239 240 typedef struct FxVerifierThreadTableEntry *pFxVerifierThreadTableEntry; 241 /* 242 * This lock performs the same actions as the base 243 * FxLock, but provides additional tracking of lock 244 * order to help detect and debug 245 * deadlock and recursive lock situations. 246 * 247 * It does not inherit from FxLock since this would 248 * cause a recursion chain. 249 * 250 * Since lock verification is already more costly than 251 * basic lock use, this verifier lock supports both the 252 * FAST_MUTEX and SpinLock modes in order to utilize common 253 * code to support verification of FxCallback locks. 254 * 255 * FxVerifierLocks are only allocated when WdfVerifierLock 256 * is turned on. 257 */ 258 259 class FxVerifierLock : public FxGlobalsStump { 260 261 private: 262 // Standard NT pool object identification 263 USHORT m_Type; 264 USHORT m_Size; 265 266 // Spinlock to perform our lock functionality 267 MxLock m_Lock; 268 KIRQL m_OldIrql; 269 270 // Fast Mutex for thread level verifier locks 271 MxPagedLock m_Mutex; 272 273 // 274 // Verifier per lock working values, protected 275 // by our m_Lock 276 // 277 FxObject* m_ParentObject; 278 MxThread m_OwningThread; 279 USHORT m_Order; 280 281 // True if its a Mutex based (thread context) lock 282 BOOLEAN m_UseMutex; 283 284 // True if its used as a Callback lock 285 BOOLEAN m_CallbackLock; 286 287 // 288 // This is the link for the per thread lock chain. 289 // 290 FxVerifierLock* m_OwnedLink; 291 292 private: 293 FxVerifierLock( 294 PFX_DRIVER_GLOBALS FxDriverGlobals 295 ) : 296 FxGlobalsStump(FxDriverGlobals) 297 { 298 } 299 300 void 301 InitializeLockOrder( 302 VOID 303 ); 304 305 void 306 FxVerifierLockDumpDetails( 307 __in FxVerifierLock* Lock, 308 __in PVOID curThread, 309 __in FxVerifierLock* PerThreadList 310 ); 311 312 private: 313 // 314 // This constructor is used by internal object 315 // locks, which always use a spinlock. 316 // 317 FxVerifierLock( 318 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 319 __in FxObject* ParentObject 320 ) : 321 FxGlobalsStump(FxDriverGlobals) 322 { 323 m_Type = FX_TYPE_VERIFIERLOCK; 324 m_Size = sizeof(FxVerifierLock); 325 326 m_ParentObject = ParentObject; 327 328 m_OwningThread = NULL; 329 m_OwnedLink = NULL; 330 m_Order = FX_LOCK_ORDER_UNKNOWN; 331 332 m_ThreadTableEntry.Thread = NULL; 333 m_ThreadTableEntry.PerThreadPassiveLockList = NULL; 334 m_ThreadTableEntry.PerThreadDispatchLockList = NULL; 335 336 m_UseMutex = FALSE; 337 m_CallbackLock = FALSE; 338 339 InitializeLockOrder(); 340 } 341 342 _Must_inspect_result_ 343 __inline 344 NTSTATUS 345 Initialize( 346 ) 347 { 348 NTSTATUS status; 349 350 if (m_UseMutex) { 351 status = m_Mutex.Initialize(); 352 353 if (!NT_SUCCESS(status)) { 354 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, 355 "Unable to initialize paged lock for VerifierLock 0x%p " 356 "status %!STATUS!", 357 this, status); 358 return status; 359 } 360 } 361 362 return STATUS_SUCCESS; 363 } 364 365 // 366 // This constructor is used by the Callback lock 367 // functions when verifer is on. 368 // 369 // The lock utlizes the callback lock order table entries to 370 // set its level. 371 // 372 FxVerifierLock( 373 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 374 __in FxObject* ParentObject, 375 __in BOOLEAN UseMutex 376 ) : 377 FxGlobalsStump(FxDriverGlobals) 378 { 379 380 m_Type = FX_TYPE_VERIFIERLOCK; 381 m_Size = sizeof(FxVerifierLock); 382 383 m_ParentObject = ParentObject; 384 385 m_OwningThread = NULL; 386 m_OwnedLink = NULL; 387 m_Order = FX_LOCK_ORDER_UNKNOWN; 388 389 m_ThreadTableEntry.Thread = NULL; 390 m_ThreadTableEntry.PerThreadPassiveLockList = NULL; 391 m_ThreadTableEntry.PerThreadDispatchLockList = NULL; 392 393 // Different verifier table 394 m_CallbackLock = TRUE; 395 396 if (UseMutex) { 397 m_UseMutex = TRUE; 398 } 399 else { 400 m_UseMutex = FALSE; 401 } 402 403 InitializeLockOrder(); 404 } 405 406 public: 407 408 _Must_inspect_result_ 409 __inline 410 static 411 NTSTATUS 412 CreateAndInitialize( 413 __out FxVerifierLock ** VerifierLock, 414 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 415 __in FxObject* ParentObject, 416 __in BOOLEAN UseMutex 417 ) 418 { 419 NTSTATUS status; 420 FxVerifierLock * verifierLock; 421 422 verifierLock = new (FxDriverGlobals) FxVerifierLock(FxDriverGlobals, 423 ParentObject, 424 UseMutex); 425 if (NULL == verifierLock) { 426 status = STATUS_INSUFFICIENT_RESOURCES; 427 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 428 "Failed to allocate verifier lock, returning %!STATUS!", 429 status); 430 goto exit; 431 } 432 433 status = verifierLock->Initialize(); 434 if (!NT_SUCCESS(status)) { 435 delete verifierLock; 436 goto exit; 437 } 438 439 *VerifierLock = verifierLock; 440 441 exit: 442 return status; 443 } 444 445 _Must_inspect_result_ 446 __inline 447 static 448 NTSTATUS 449 CreateAndInitialize( 450 __out FxVerifierLock ** VerifierLock, 451 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 452 __in FxObject* ParentObject 453 ) 454 { 455 NTSTATUS status; 456 FxVerifierLock * verifierLock; 457 458 verifierLock = new (FxDriverGlobals) FxVerifierLock(FxDriverGlobals, 459 ParentObject); 460 if (NULL == verifierLock) { 461 status = STATUS_INSUFFICIENT_RESOURCES; 462 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 463 "Failed to allocate verifier lock, returning %!STATUS!", 464 status); 465 goto exit; 466 } 467 468 status = verifierLock->Initialize(); 469 if (!NT_SUCCESS(status)) { 470 delete verifierLock; 471 goto exit; 472 } 473 474 *VerifierLock = verifierLock; 475 476 exit: 477 return status; 478 } 479 480 ~FxVerifierLock( 481 VOID 482 ) 483 { 484 if (m_OwningThread != NULL) { 485 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, 486 "Lock 0x%p is being destroyed while owned by " 487 "thread 0x%p, Owning Object 0x%p", 488 this, m_OwningThread, m_ParentObject); 489 FxVerifierDbgBreakPoint(GetDriverGlobals()); 490 } 491 } 492 493 VOID 494 Lock( 495 __out PKIRQL PreviousIrql, 496 __in BOOLEAN AtDpc 497 ); 498 499 VOID 500 Unlock( 501 __in KIRQL PreviousIrql, 502 __in BOOLEAN AtDpc 503 ); 504 505 KIRQL 506 GetLockPreviousIrql( 507 VOID 508 ); 509 510 // 511 // Instance data needed for the hash table chaining 512 // 513 FxVerifierThreadTableEntry m_ThreadTableEntry; 514 515 // 516 // Static data and methods for hash table chaining 517 // 518 static ULONG ThreadTableSize; 519 520 static KSPIN_LOCK ThreadTableLock; 521 522 static PLIST_ENTRY ThreadTable; 523 524 static 525 void 526 AllocateThreadTable( 527 __in PFX_DRIVER_GLOBALS FxDriverGlobals 528 ); 529 530 static 531 void 532 FreeThreadTable( 533 __in PFX_DRIVER_GLOBALS FxDriverGlobals 534 ); 535 536 static 537 void 538 DumpDetails( 539 __in FxVerifierLock* Lock, 540 __in MxThread curThread, 541 __in FxVerifierLock* PerThreadList 542 ); 543 544 static 545 pFxVerifierThreadTableEntry 546 GetThreadTableEntry( 547 __in MxThread curThread, 548 __in FxVerifierLock* pLock, 549 __in BOOLEAN LookupOnly 550 ); 551 552 static 553 void 554 ReleaseOrReplaceThreadTableEntry( 555 __in MxThread curThread, 556 __in FxVerifierLock* pLock 557 ); 558 }; 559 560 #endif // _FXVERIFIERLOCK_HPP_ 561 562 563