1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxDmaEnablerAPI.cpp 8 9 Abstract: 10 11 Base for WDF DMA Enabler object APIs 12 13 Environment: 14 15 Kernel mode only. 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 #include "fxdmapch.hpp" 25 26 extern "C" { 27 // #include "FxDmaEnablerAPI.tmh" 28 } 29 30 // 31 // Extern "C" the entire file 32 // 33 extern "C" { 34 35 _Must_inspect_result_ 36 __drv_maxIRQL(PASSIVE_LEVEL) 37 NTSTATUS 38 WDFEXPORT(WdfDmaEnablerCreate)( 39 __in 40 PWDF_DRIVER_GLOBALS DriverGlobals, 41 __in 42 WDFDEVICE Device, 43 __in 44 WDF_DMA_ENABLER_CONFIG * Config, 45 __in_opt 46 WDF_OBJECT_ATTRIBUTES * Attributes, 47 __out 48 WDFDMAENABLER * DmaEnablerHandle 49 ) 50 { 51 FxDmaEnabler * pDmaEnabler; 52 FxDeviceBase * pDevice; 53 NTSTATUS status; 54 WDFDMAENABLER handle; 55 PFX_DRIVER_GLOBALS pFxDriverGlobals; 56 FxObject * pParent; 57 WDF_DMA_ENABLER_CONFIG dmaConfig; 58 59 // 60 // Validate the Device handle 61 // 62 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 63 Device, 64 FX_TYPE_DEVICE_BASE, 65 (PVOID *) &pDevice, 66 &pFxDriverGlobals); 67 68 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 69 if (!NT_SUCCESS(status)) { 70 return status; 71 } 72 73 FxPointerNotNull(pFxDriverGlobals, DmaEnablerHandle); 74 FxPointerNotNull(pFxDriverGlobals, Config); 75 76 *DmaEnablerHandle = NULL; 77 78 status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); 79 80 if (!NT_SUCCESS(status)) { 81 return status; 82 } 83 84 if (Attributes != NULL && Attributes->ParentObject != NULL) { 85 FxObjectHandleGetPtr(pFxDriverGlobals, 86 Attributes->ParentObject, 87 FX_TYPE_OBJECT, 88 (PVOID*)&pParent); 89 90 if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { 91 FxDeviceBase * pSearchDevice; 92 93 // 94 // If a parent object is passed-in it must be descendent of device. 95 // DmaEnabler stores device and uses it during dispose 96 // (to remove it from dmaenabler list maintained at device level), 97 // so DmaEnabler cannot outlive device. 98 // 99 100 pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL); 101 102 if (pSearchDevice == NULL) { 103 status = STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; 104 105 DoTraceLevelMessage( 106 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 107 "Attributes->ParentObject 0x%p must have WDFDEVICE as an " 108 "eventual ancestor, %!STATUS!", 109 Attributes->ParentObject, status); 110 111 return status; 112 } 113 else if (pSearchDevice != pDevice) { 114 status = STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; 115 116 DoTraceLevelMessage( 117 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 118 "Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but " 119 "not the same WDFDEVICE 0x%p passed to WdfDmaEnablerCreate, " 120 "%!STATUS!", 121 Attributes->ParentObject, pSearchDevice->GetHandle(), 122 Device, status); 123 124 return status; 125 } 126 } 127 else { 128 // 129 // For < 1.11 drivers we only allow pDevice to be the parent 130 // since that is what we were blindly setting the parent to. 131 // 132 // Using the passed-in parent for such drivers could cause 133 // side-effects such as earlier deletion of DmaEnabler object. So 134 // we don't do that. 135 // 136 // We cause this verifier breakpoint to warn downlevel drivers 137 // that the parent they passed in gets ignored. 138 // 139 if (pParent != pDevice) { 140 DoTraceLevelMessage( 141 pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDMA, 142 "For drivers bound to version <= 1.9 " 143 "WdfDmaEnablerCreate uses WDFDEVICE as the " 144 "parent object for the dma enabler object. " 145 "Attributes->ParentObject 0x%p, which is different from " 146 "WDFDEVICE 0x%p, gets ignored. Please note that DmaEnabler " 147 "would be disposed only when device is disposed.", 148 Attributes->ParentObject, Device); 149 150 if (pFxDriverGlobals->IsDownlevelVerificationEnabled()) { 151 FxVerifierDbgBreakPoint(pFxDriverGlobals); 152 } 153 } 154 155 pParent = pDevice; 156 } 157 } 158 else { 159 pParent = pDevice; 160 } 161 162 { 163 ULONG expectedSize = pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) ? 164 sizeof(WDF_DMA_ENABLER_CONFIG) : 165 sizeof(WDF_DMA_ENABLER_CONFIG_V1_9); 166 167 if (Config->Size != expectedSize) { 168 status = STATUS_INFO_LENGTH_MISMATCH; 169 170 DoTraceLevelMessage( 171 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 172 "WDF_DMA_ENABLER_CONFIG Size 0x%x, expected 0x%x, %!STATUS!", 173 Config->Size, expectedSize, status); 174 175 return status; 176 } 177 178 179 // 180 // Normalize DMA config structure if necessary. 181 // 182 if (Config->Size < sizeof(WDF_DMA_ENABLER_CONFIG)) { 183 // 184 // Init new fields to default values. 185 // 186 WDF_DMA_ENABLER_CONFIG_INIT(&dmaConfig, 187 Config->Profile, 188 Config->MaximumLength); 189 // 190 // Copy over existing fields and readjust the struct size. 191 // 192 RtlCopyMemory(&dmaConfig, Config, Config->Size); 193 dmaConfig.Size = sizeof(dmaConfig); 194 195 // 196 // Use new config structure from now on. 197 // 198 Config = &dmaConfig; 199 } 200 } 201 202 switch (Config->Profile) { 203 case WdfDmaProfilePacket: 204 case WdfDmaProfileScatterGather: 205 case WdfDmaProfilePacket64: 206 case WdfDmaProfileScatterGather64: 207 case WdfDmaProfileScatterGather64Duplex: 208 case WdfDmaProfileScatterGatherDuplex: 209 case WdfDmaProfileSystem: 210 case WdfDmaProfileSystemDuplex: 211 break; 212 default: 213 status = STATUS_INVALID_PARAMETER; 214 DoTraceLevelMessage( 215 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 216 "DMA Profile value %d is unknown, %!STATUS!", 217 Config->Profile, status); 218 return status; 219 } 220 221 if (Config->MaximumLength == 0) { 222 status = STATUS_INVALID_PARAMETER; 223 224 DoTraceLevelMessage( 225 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 226 "Config MaximumLength of zero is invalid, %!STATUS!", 227 status); 228 229 return status; 230 } 231 232 // 233 // Ok: create a new DmaEnabler 234 // 235 pDmaEnabler = new(pFxDriverGlobals, Attributes) 236 FxDmaEnabler( pFxDriverGlobals ); 237 238 if (pDmaEnabler == NULL) { 239 status = STATUS_INSUFFICIENT_RESOURCES; 240 241 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 242 "Could not allocate memory for a WDFDMAENABLER, " 243 "%!STATUS!", status); 244 245 return status; 246 } 247 248 // 249 // Assign this FxDmaEnabler to its parent FxDevice object. 250 // 251 status = pDmaEnabler->Commit(Attributes, (WDFOBJECT*)&handle, pParent); 252 253 if (NT_SUCCESS(status)) { 254 // 255 // Ok: start this DmaEnabler. 256 // 257 status = pDmaEnabler->Initialize( Config, pDevice ); 258 } 259 260 if (NT_SUCCESS(status)) { 261 // 262 // Only return a valid handle on success. 263 // 264 *DmaEnablerHandle = handle; 265 } 266 else { 267 pDmaEnabler->DeleteFromFailedCreate(); 268 } 269 270 return status; 271 } 272 273 __drv_maxIRQL(DISPATCH_LEVEL) 274 size_t 275 WDFEXPORT(WdfDmaEnablerGetMaximumLength)( 276 __in 277 PWDF_DRIVER_GLOBALS DriverGlobals, 278 __in 279 WDFDMAENABLER DmaEnabler 280 ) 281 { 282 FxDmaEnabler * pDmaEnabler; 283 284 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 285 DmaEnabler, 286 FX_TYPE_DMA_ENABLER, 287 (PVOID *) &pDmaEnabler); 288 289 return pDmaEnabler->GetMaximumLength(); 290 } 291 292 __drv_maxIRQL(DISPATCH_LEVEL) 293 size_t 294 WDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements)( 295 __in 296 PWDF_DRIVER_GLOBALS DriverGlobals, 297 __in 298 WDFDMAENABLER DmaEnabler 299 ) 300 { 301 FxDmaEnabler * pDmaEnabler; 302 303 FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), 304 DmaEnabler, 305 FX_TYPE_DMA_ENABLER, 306 (PVOID *) &pDmaEnabler); 307 308 return pDmaEnabler->GetMaxSGElements(); 309 } 310 311 312 __drv_maxIRQL(PASSIVE_LEVEL) 313 VOID 314 WDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements)( 315 __in 316 PWDF_DRIVER_GLOBALS DriverGlobals, 317 __in 318 WDFDMAENABLER DmaEnabler, 319 __in 320 __drv_when(MaximumElements == 0, __drv_reportError(MaximumElements cannot be zero)) 321 size_t MaximumElements 322 ) 323 { 324 PFX_DRIVER_GLOBALS pFxDriverGlobals; 325 FxDmaEnabler * pDmaEnabler; 326 NTSTATUS status; 327 328 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 329 DmaEnabler, 330 FX_TYPE_DMA_ENABLER, 331 (PVOID *) &pDmaEnabler, 332 &pFxDriverGlobals); 333 334 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 335 if (!NT_SUCCESS(status)) { 336 return; 337 } 338 339 if (MaximumElements == 0) { 340 DoTraceLevelMessage( 341 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 342 "Cannot set MaximumElements of zero on WDFDMAENABLER %p", 343 DmaEnabler); 344 return; 345 } 346 347 pDmaEnabler->SetMaxSGElements(MaximumElements); 348 } 349 350 __drv_maxIRQL(DISPATCH_LEVEL) 351 size_t 352 WDFEXPORT(WdfDmaEnablerGetFragmentLength)( 353 __in 354 PWDF_DRIVER_GLOBALS DriverGlobals, 355 __in 356 WDFDMAENABLER DmaEnabler, 357 __in 358 WDF_DMA_DIRECTION DmaDirection 359 ) 360 { 361 FxDmaEnabler * pDmaEnabler; 362 size_t length; 363 PFX_DRIVER_GLOBALS pFxDriverGlobals; 364 365 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 366 DmaEnabler, 367 FX_TYPE_DMA_ENABLER, 368 (PVOID *) &pDmaEnabler, 369 &pFxDriverGlobals); 370 371 switch (DmaDirection) { 372 373 case WdfDmaDirectionReadFromDevice: 374 length = pDmaEnabler->GetReadDmaDescription()->MaximumFragmentLength; 375 break; 376 377 case WdfDmaDirectionWriteToDevice: 378 length = pDmaEnabler->GetWriteDmaDescription()->MaximumFragmentLength; 379 break; 380 381 default: 382 length = 0; 383 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 384 "Invalid value for Dma direction %d, %p", 385 DmaDirection, DmaEnabler); 386 FxVerifierDbgBreakPoint(pFxDriverGlobals); 387 break; 388 } 389 390 return length; 391 } 392 393 __drv_maxIRQL(DISPATCH_LEVEL) 394 PDMA_ADAPTER 395 WDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter)( 396 __in 397 PWDF_DRIVER_GLOBALS DriverGlobals, 398 __in 399 WDFDMAENABLER DmaEnabler, 400 __in 401 WDF_DMA_DIRECTION DmaDirection 402 ) 403 { 404 PDMA_ADAPTER adapter; 405 PFX_DRIVER_GLOBALS pFxDriverGlobals; 406 FxDmaEnabler * pDmaEnabler; 407 408 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 409 DmaEnabler, 410 FX_TYPE_DMA_ENABLER, 411 (PVOID *) &pDmaEnabler, 412 &pFxDriverGlobals); 413 414 switch (DmaDirection) { 415 416 case WdfDmaDirectionReadFromDevice: 417 adapter = pDmaEnabler->GetReadDmaDescription()->AdapterObject; 418 break; 419 420 case WdfDmaDirectionWriteToDevice: 421 adapter = pDmaEnabler->GetWriteDmaDescription()->AdapterObject; 422 break; 423 424 default: 425 adapter = NULL; 426 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 427 "Invalid value for Dma direction %d, %p", 428 DmaDirection, DmaEnabler); 429 FxVerifierDbgBreakPoint(pFxDriverGlobals); 430 break; 431 } 432 433 return adapter; 434 } 435 436 _Must_inspect_result_ 437 __drv_maxIRQL(PASSIVE_LEVEL) 438 NTSTATUS 439 WDFEXPORT(WdfDmaEnablerConfigureSystemProfile)( 440 __in 441 PWDF_DRIVER_GLOBALS DriverGlobals, 442 __in 443 WDFDMAENABLER DmaEnabler, 444 __in 445 PWDF_DMA_SYSTEM_PROFILE_CONFIG ProfileConfig, 446 __in 447 WDF_DMA_DIRECTION ConfigDirection 448 ) 449 { 450 PFX_DRIVER_GLOBALS pFxDriverGlobals; 451 FxDmaEnabler * pDmaEnabler; 452 453 NTSTATUS status; 454 455 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 456 DmaEnabler, 457 FX_TYPE_DMA_ENABLER, 458 (PVOID *) &pDmaEnabler, 459 &pFxDriverGlobals); 460 461 // 462 // Verify the DMA config 463 // 464 465 if (ProfileConfig == NULL) 466 { 467 status = STATUS_INVALID_PARAMETER; 468 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 469 "ProfileConfig must be non-null, %!STATUS!", 470 status); 471 FxVerifierDbgBreakPoint(pFxDriverGlobals); 472 return status; 473 } 474 475 if (ProfileConfig->Size != sizeof(WDF_DMA_SYSTEM_PROFILE_CONFIG)) 476 { 477 status = STATUS_INFO_LENGTH_MISMATCH; 478 479 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 480 "WDF_DMA_SYSTEM_PROFILE_CONFIG Size 0x%x, expected 0x%x, %!STATUS!", 481 ProfileConfig->Size, sizeof(WDF_DMA_SYSTEM_PROFILE_CONFIG), status); 482 483 FxVerifierDbgBreakPoint(pFxDriverGlobals); 484 485 return status; 486 } 487 488 if (ProfileConfig->DmaDescriptor == NULL) 489 { 490 status = STATUS_INVALID_PARAMETER; 491 492 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 493 "ProfileConfig (%p) may not have NULL DmaDescriptor, %!STATUS!", 494 ProfileConfig, status); 495 496 FxVerifierDbgBreakPoint(pFxDriverGlobals); 497 498 return status; 499 } 500 501 if (ConfigDirection != WdfDmaDirectionReadFromDevice && 502 ConfigDirection != WdfDmaDirectionWriteToDevice) { 503 status = STATUS_INVALID_PARAMETER; 504 DoTraceLevelMessage( 505 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, 506 "ConfigDirection 0x%x is an invalid value, %!STATUS!", 507 ConfigDirection, status); 508 return status; 509 } 510 511 status = pDmaEnabler->ConfigureSystemAdapter(ProfileConfig, 512 ConfigDirection); 513 return status; 514 } 515 516 } // extern "C" 517