1 /*++ 2 Copyright (c) Microsoft. All rights reserved. 3 4 Module Name: 5 6 SelfManagedIoStateMachine.cpp 7 8 Abstract: 9 10 This module implements the self managed io state machine start / stop logic 11 in the framework. 12 13 Author: 14 15 16 17 Environment: 18 Both kernel and user mode 19 20 Revision History: 21 22 23 24 --*/ 25 26 #include "pnppriv.hpp" 27 28 extern "C" { 29 #if defined(EVENT_TRACING) 30 #include "SelfManagedIoStateMachine.tmh" 31 #endif 32 } 33 34 // * - We can get a restart from the created state if a PDO is newly enumerated 35 // but was disabled on a previous enumeration. Treat restart as an init 36 // in this case. 37 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_CreatedStates[] = 38 { 39 { SelfManagedIoEventStart, FxSelfManagedIoInit DEBUGGED_EVENT }, 40 { SelfManagedIoEventFlush, FxSelfManagedIoCreated DEBUGGED_EVENT }, 41 { SelfManagedIoEventCleanup, FxSelfManagedIoFinal DEBUGGED_EVENT }, 42 }; 43 44 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_InitFailedStates[] = 45 { 46 { SelfManagedIoEventSuspend, FxSelfManagedIoInitFailed DEBUGGED_EVENT }, 47 { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT }, 48 }; 49 50 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StartedStates[] = 51 { 52 { SelfManagedIoEventSuspend, FxSelfManagedIoSuspending DEBUGGED_EVENT }, 53 }; 54 55 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StoppedStates[] = 56 { 57 { SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT }, 58 { SelfManagedIoEventSuspend, FxSelfManagedIoStopped DEBUGGED_EVENT }, 59 { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT }, 60 }; 61 62 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FailedStates[] = 63 { 64 { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT }, 65 { SelfManagedIoEventSuspend, FxSelfManagedIoFailed DEBUGGED_EVENT }, 66 }; 67 68 const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FlushedStates[] = 69 { 70 { SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT }, 71 { SelfManagedIoEventCleanup, FxSelfManagedIoCleanup DEBUGGED_EVENT }, 72 { SelfManagedIoEventFlush, FxSelfManagedIoFlushed TRAP_ON_EVENT }, 73 }; 74 75 const FxSelfManagedIoStateTable FxSelfManagedIoMachine::m_StateTable[] = 76 { 77 // FxSelfManagedIoCreated 78 { NULL, 79 FxSelfManagedIoMachine::m_CreatedStates, 80 ARRAY_SIZE(FxSelfManagedIoMachine::m_CreatedStates), 81 }, 82 83 // FxSelfManagedIoInit 84 { FxSelfManagedIoMachine::Init, 85 NULL, 86 0, 87 }, 88 89 // FxSelfManagedIoInitFailed 90 { NULL, 91 FxSelfManagedIoMachine::m_InitFailedStates, 92 ARRAY_SIZE(FxSelfManagedIoMachine::m_InitFailedStates), 93 }, 94 95 // FxSelfManagedIoStarted 96 { NULL, 97 FxSelfManagedIoMachine::m_StartedStates, 98 ARRAY_SIZE(FxSelfManagedIoMachine::m_StartedStates), 99 }, 100 101 // FxSelfManagedIoSuspending 102 { FxSelfManagedIoMachine::Suspending, 103 NULL, 104 0, 105 }, 106 107 // FxSelfManagedIoStopped 108 { NULL, 109 FxSelfManagedIoMachine::m_StoppedStates, 110 ARRAY_SIZE(FxSelfManagedIoMachine::m_StoppedStates), 111 }, 112 113 // FxSelfManagedIoRestarting 114 { FxSelfManagedIoMachine::Restarting, 115 NULL, 116 0, 117 }, 118 119 // FxSelfManagedIoFailed 120 { NULL, 121 FxSelfManagedIoMachine::m_FailedStates, 122 ARRAY_SIZE(FxSelfManagedIoMachine::m_FailedStates), 123 }, 124 125 // FxSelfManagedIoFlushing 126 { FxSelfManagedIoMachine::Flushing, 127 NULL, 128 0, 129 }, 130 131 // FxSelfManagedIoFlushed 132 { NULL, 133 FxSelfManagedIoMachine::m_FlushedStates, 134 ARRAY_SIZE(FxSelfManagedIoMachine::m_FlushedStates), 135 }, 136 137 // FxSelfManagedIoCleanup 138 { FxSelfManagedIoMachine::Cleanup, 139 NULL, 140 0, 141 }, 142 143 // FxSelfManagedIoFinal 144 { NULL, 145 NULL, 146 0, 147 }, 148 }; 149 150 FxSelfManagedIoMachine::FxSelfManagedIoMachine( 151 __in FxPkgPnp* PkgPnp 152 ) 153 { 154 m_PkgPnp = PkgPnp; 155 156 m_EventHistoryIndex = 0; 157 m_StateHistoryIndex = 0; 158 159 m_CurrentState = FxSelfManagedIoCreated; 160 161 RtlZeroMemory(&m_Events, sizeof(m_Events)); 162 RtlZeroMemory(&m_States, sizeof(m_States)); 163 164 // 165 // Make sure we can fit the state into a byte 166 // 167 ASSERT(FxSelfManagedIoMax <= 0xFF); 168 } 169 170 NTSTATUS 171 FxSelfManagedIoMachine::_CreateAndInit( 172 __deref_out FxSelfManagedIoMachine** SelfManagedIoMachine, 173 __in FxPkgPnp* PkgPnp 174 ) 175 { 176 NTSTATUS status; 177 FxSelfManagedIoMachine * selfManagedIoMachine; 178 179 *SelfManagedIoMachine = NULL; 180 181 selfManagedIoMachine = new (PkgPnp->GetDriverGlobals()) FxSelfManagedIoMachine( 182 PkgPnp 183 ); 184 185 if (selfManagedIoMachine == NULL) { 186 DoTraceLevelMessage( 187 PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 188 "Self managed I/O state machine allocation failed for " 189 "WDFDEVICE 0x%p", 190 PkgPnp->GetDevice()->GetHandle()); 191 192 return STATUS_INSUFFICIENT_RESOURCES; 193 } 194 195 status = selfManagedIoMachine->m_StateMachineLock.Initialize(); 196 if (!NT_SUCCESS(status)) { 197 DoTraceLevelMessage( 198 PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, 199 "Self managed I/O state machine lock initialization failed for " 200 "WDFDEVICE 0x%p, %!STATUS!", 201 PkgPnp->GetDevice()->GetHandle(), 202 status); 203 204 delete selfManagedIoMachine; 205 206 return status; 207 } 208 209 *SelfManagedIoMachine = selfManagedIoMachine; 210 211 return status; 212 } 213 214 215 VOID 216 FxSelfManagedIoMachine::InitializeMachine( 217 __in PWDF_PNPPOWER_EVENT_CALLBACKS Callbacks 218 ) 219 /*++ 220 221 Routine Description: 222 Sets all the function event callbacks. 223 224 Arguments: 225 Callbacks - list of callbacks to set 226 227 Return Value: 228 None 229 230 --*/ 231 { 232 m_DeviceSelfManagedIoCleanup.m_Method = Callbacks->EvtDeviceSelfManagedIoCleanup; 233 m_DeviceSelfManagedIoFlush.m_Method = Callbacks->EvtDeviceSelfManagedIoFlush; 234 m_DeviceSelfManagedIoInit.m_Method = Callbacks->EvtDeviceSelfManagedIoInit; 235 m_DeviceSelfManagedIoSuspend.m_Method = Callbacks->EvtDeviceSelfManagedIoSuspend; 236 m_DeviceSelfManagedIoRestart.m_Method = Callbacks->EvtDeviceSelfManagedIoRestart; 237 } 238 239 WDFDEVICE 240 FxSelfManagedIoMachine::GetDeviceHandle( 241 VOID 242 ) 243 { 244 return m_PkgPnp->GetDevice()->GetHandle(); 245 } 246 247 _Must_inspect_result_ 248 NTSTATUS 249 FxSelfManagedIoMachine::ProcessEvent( 250 __in FxSelfManagedIoEvents Event 251 ) 252 /*++ 253 254 Routine Description: 255 Processes an event and runs it through the state machine. Unlike other 256 state machines in the framework, this one acquires lock in the event 257 processing function rather then relying on the caller to do so. 258 259 Arguments: 260 Event - The event to feed into the state machine. 261 262 Return Value: 263 result of the event 264 265 --*/ 266 { 267 const FxSelfManagedIoStateTable* entry; 268 FxSelfManagedIoStates newState; 269 NTSTATUS status; 270 271 m_StateMachineLock.AcquireLock(m_PkgPnp->GetDriverGlobals()); 272 273 m_Events.History[m_EventHistoryIndex] = (UCHAR) Event; 274 m_EventHistoryIndex = (m_EventHistoryIndex + 1) % 275 (sizeof(m_Events.History)/sizeof(m_Events.History[0])); 276 277 entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated]; 278 newState = FxSelfManagedIoMax; 279 280 for (ULONG i = 0; i < entry->TargetStatesCount; i++) { 281 if (entry->TargetStates[i].SelfManagedIoEvent == Event) { 282 DO_EVENT_TRAP(&entry->TargetStates[i]); 283 newState = entry->TargetStates[i].SelfManagedIoState; 284 break; 285 } 286 } 287 288 if (newState == FxSelfManagedIoMax) { 289 // 290 // We always can handle io increment/decrement from any state, but we 291 // should not be dropping any other events from this state. 292 // 293 294 COVERAGE_TRAP(); 295 } 296 297 status = STATUS_SUCCESS; 298 299 while (newState != FxSelfManagedIoMax) { 300 DoTraceLevelMessage( 301 m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, 302 "WDFDEVICE 0x%p !devobj 0x%p entering self managed io state " 303 "%!FxSelfManagedIoStates! from %!FxSelfManagedIoStates!", 304 m_PkgPnp->GetDevice()->GetHandle(), 305 m_PkgPnp->GetDevice()->GetDeviceObject(), 306 newState, m_CurrentState); 307 308 m_States.History[m_StateHistoryIndex] = (UCHAR) newState; 309 m_StateHistoryIndex = (m_StateHistoryIndex + 1) % 310 (sizeof(m_States.History)/sizeof(m_States.History[0])); 311 312 m_CurrentState = (BYTE) newState; 313 entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated]; 314 315 if (entry->StateFunc != NULL) { 316 newState = entry->StateFunc(this, &status); 317 } 318 else { 319 newState = FxSelfManagedIoMax; 320 } 321 } 322 323 m_StateMachineLock.ReleaseLock(m_PkgPnp->GetDriverGlobals()); 324 325 return status; 326 } 327 328 FxSelfManagedIoStates 329 FxSelfManagedIoMachine::Init( 330 __in FxSelfManagedIoMachine* This, 331 __out PNTSTATUS Status 332 ) 333 /*++ 334 335 Routine Description: 336 Calls the event callback for initializing self managed io. 337 338 Arguments: 339 This - instance of the state machine 340 341 Status - result of the event callback into the driver 342 343 Return Value: 344 new machine state 345 346 --*/ 347 { 348 *Status = This->m_DeviceSelfManagedIoInit.Invoke(This->GetDeviceHandle()); 349 350 if (NT_SUCCESS(*Status)) { 351 return FxSelfManagedIoStarted; 352 } 353 else { 354 return FxSelfManagedIoInitFailed; 355 } 356 } 357 358 FxSelfManagedIoStates 359 FxSelfManagedIoMachine::Suspending( 360 __in FxSelfManagedIoMachine* This, 361 __out PNTSTATUS Status 362 ) 363 /*++ 364 365 Routine Description: 366 Invokes the self managed io suspend event callback. Upon failure goes to 367 the failed state and awaits teardown of the stack. 368 369 Arguments: 370 This - instance of the state machine 371 372 Status - result of the event callback into the driver 373 374 Return Value: 375 new machine state 376 377 --*/ 378 { 379 *Status = This->m_DeviceSelfManagedIoSuspend.Invoke(This->GetDeviceHandle()); 380 381 if (NT_SUCCESS(*Status)) { 382 return FxSelfManagedIoStopped; 383 } 384 else { 385 return FxSelfManagedIoFailed; 386 } 387 } 388 389 FxSelfManagedIoStates 390 FxSelfManagedIoMachine::Restarting( 391 __in FxSelfManagedIoMachine* This, 392 __out PNTSTATUS Status 393 ) 394 /*++ 395 396 Routine Description: 397 Invokes the self managed io event callback for restarting self managed io 398 from the stopped state. 399 400 Arguments: 401 This - instance of the state machine 402 403 Status - result of the event callback into the driver 404 405 Return Value: 406 new machine state 407 408 --*/ 409 { 410 *Status = This->m_DeviceSelfManagedIoRestart.Invoke(This->GetDeviceHandle()); 411 412 if (NT_SUCCESS(*Status)) { 413 return FxSelfManagedIoStarted; 414 } 415 else { 416 return FxSelfManagedIoFailed; 417 } 418 } 419 420 FxSelfManagedIoStates 421 FxSelfManagedIoMachine::Flushing( 422 __in FxSelfManagedIoMachine* This, 423 __out PNTSTATUS Status 424 ) 425 /*++ 426 427 Routine Description: 428 Calls the self managed io flush routine. 429 430 Arguments: 431 This - instance of the state machine 432 433 Status - result of the event callback into the driver 434 435 Return Value: 436 FxSelfManagedIoFlushed 437 438 --*/ 439 { 440 UNREFERENCED_PARAMETER(Status); 441 This->m_DeviceSelfManagedIoFlush.Invoke(This->GetDeviceHandle()); 442 return FxSelfManagedIoFlushed; 443 } 444 445 FxSelfManagedIoStates 446 FxSelfManagedIoMachine::Cleanup( 447 __in FxSelfManagedIoMachine* This, 448 __out PNTSTATUS Status 449 ) 450 /*++ 451 452 Routine Description: 453 Calls the self managed io cleanup routine. 454 455 Arguments: 456 This - instance of the state machine 457 458 Status - result of the event callback into the driver 459 460 Return Value: 461 FxSelfManagedIoFinal 462 463 --*/ 464 { 465 UNREFERENCED_PARAMETER(Status); 466 467 This->m_DeviceSelfManagedIoCleanup.Invoke(This->GetDeviceHandle()); 468 return FxSelfManagedIoFinal; 469 } 470