1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxDriverApi.cpp 8 9 Abstract: 10 11 This module contains the "C" interface for the FxDriver object. 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 27 // Tracing support 28 extern "C" { 29 #include <ntverp.h> 30 // #include "FxDriverApi.tmh" 31 } 32 33 #include "fxtelemetry.hpp" 34 35 // 36 // extern the whole file 37 // 38 extern "C" { 39 40 // 41 // Driver Pool Allocations 42 // 43 44 45 __drv_maxIRQL(PASSIVE_LEVEL) 46 PWSTR 47 STDCALL 48 WDFEXPORT(WdfDriverGetRegistryPath)( 49 __in 50 PWDF_DRIVER_GLOBALS DriverGlobals, 51 __in 52 WDFDRIVER Driver 53 ) 54 { 55 DDI_ENTRY(); 56 57 PFX_DRIVER_GLOBALS pFxDriverGlobals; 58 NTSTATUS status; 59 FxDriver *pDriver; 60 61 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 62 Driver, 63 FX_TYPE_DRIVER, 64 (PVOID *)&pDriver, 65 &pFxDriverGlobals); 66 67 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 68 if (!NT_SUCCESS(status)) { 69 return NULL; 70 } 71 72 return pDriver->GetRegistryPathUnicodeString()->Buffer; 73 } 74 75 VOID 76 RosInitWdf(); 77 78 _Must_inspect_result_ 79 __drv_maxIRQL(PASSIVE_LEVEL) 80 NTSTATUS 81 STDCALL 82 WDFEXPORT(WdfDriverCreate)( 83 __in 84 PWDF_DRIVER_GLOBALS DriverGlobals, 85 __in 86 MdDriverObject DriverObject, 87 __in 88 PCUNICODE_STRING RegistryPath, 89 __in_opt 90 PWDF_OBJECT_ATTRIBUTES DriverAttributes, 91 __in 92 PWDF_DRIVER_CONFIG DriverConfig, 93 __out_opt 94 WDFDRIVER* Driver 95 ) 96 { 97 DDI_ENTRY(); 98 99 PFX_DRIVER_GLOBALS pFxDriverGlobals; 100 FxDriver *pDriver; 101 NTSTATUS status; 102 WDFDRIVER hDriver; 103 const LONG validFlags = WdfDriverInitNonPnpDriver | 104 WdfDriverInitNoDispatchOverride; 105 106 RosInitWdf(); 107 DriverGlobals = WdfDriverGlobals; 108 109 hDriver = NULL; 110 pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); 111 112 FxPointerNotNull(pFxDriverGlobals, DriverObject); 113 FxPointerNotNull(pFxDriverGlobals, RegistryPath); 114 FxPointerNotNull(pFxDriverGlobals, DriverConfig); 115 116 // 117 // Validate the size of the input Driver Config structure. The size changed 118 // after v1.1. The size is the same for v1.1 and v1.0, verify that. 119 // 120 WDFCASSERT(sizeof(WDF_DRIVER_CONFIG_V1_0) == sizeof(WDF_DRIVER_CONFIG_V1_1)); 121 122 if (DriverConfig->Size != sizeof(WDF_DRIVER_CONFIG) 123 && 124 DriverConfig->Size != sizeof(WDF_DRIVER_CONFIG_V1_1)) { 125 126 status = STATUS_INFO_LENGTH_MISMATCH; 127 DoTraceLevelMessage( 128 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, 129 "WDF_DRIVER_CONFIG got Size %d, expected v1.1 size %d or cur ver size %d, %!STATUS!", 130 DriverConfig->Size, 131 sizeof(WDF_DRIVER_CONFIG_V1_1), sizeof(WDF_DRIVER_CONFIG), status); 132 133 return status; 134 } 135 136 // 137 // Validate the DriverInitFlags value in the Driver Config. 138 // 139 if ((DriverConfig->DriverInitFlags & ~validFlags) != 0) { 140 status = STATUS_INVALID_PARAMETER; 141 DoTraceLevelMessage( 142 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, 143 "DriverInitFlags 0x%x invalid, valid flags are 0x%x, %!STATUS!", 144 DriverConfig->DriverInitFlags, validFlags, status); 145 return status; 146 } 147 148 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 149 if (!NT_SUCCESS(status)) { 150 return status; 151 } 152 153 status = FxValidateUnicodeString(pFxDriverGlobals, RegistryPath); 154 if (!NT_SUCCESS(status)) { 155 return status; 156 } 157 158 // 159 // Driver and Public.Driver are set once WdfDriverCreate returns successfully. 160 // If they are set, that means this DDI has already been called for this 161 // client. Return an error if this occurrs. 162 // 163 if (pFxDriverGlobals->Driver != NULL || 164 pFxDriverGlobals->Public.Driver != NULL) { 165 166 status = STATUS_DRIVER_INTERNAL_ERROR; 167 168 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, 169 "WdfDriverCreate can only be called one time per " 170 "WDM PDRIVER_OBJECT %p, %!STATUS!", 171 DriverObject, status); 172 173 return status; 174 } 175 176 if (Driver != NULL) { 177 *Driver = NULL; 178 } 179 180 // 181 // Initializing the tag requires initializing the driver name first. 182 // 183 FxDriver::_InitializeDriverName(pFxDriverGlobals, RegistryPath); 184 185 // 186 // Initialize the tag before any allocation so that we can use the correct 187 // tag value when allocating on behalf of the driver (for all allocations, 188 // including FxDriver). 189 // 190 // Use the client's driver tag value if they specified one. First check 191 // to make sure the size of the structure is the new size (vs the old size 192 // in v1.1). 193 // 194 // ' kdD' - was the default tag in many DDKs, don't allow its use. 195 // 196 if (DriverConfig->Size == sizeof(WDF_DRIVER_CONFIG) && 197 DriverConfig->DriverPoolTag != 0x0 && 198 DriverConfig->DriverPoolTag != ' kdD') { 199 // 200 // Copy directly using the driver's value 201 // 202 pFxDriverGlobals->Tag = DriverConfig->DriverPoolTag; 203 pFxDriverGlobals->Public.DriverTag = DriverConfig->DriverPoolTag; 204 } 205 else { 206 // 207 // Derive the value from the driver's service name 208 // 209 FxDriver::_InitializeTag(pFxDriverGlobals, DriverConfig); 210 } 211 212 // 213 // Check to see if this is an NT4 style device driver. If so, fail if they 214 // specified an AddDevice routine. If no dispatch override is set, 215 // do not do any checking at all. 216 // 217 if (DriverConfig->DriverInitFlags & WdfDriverInitNoDispatchOverride) { 218 DO_NOTHING(); 219 } 220 else if ((DriverConfig->DriverInitFlags & WdfDriverInitNonPnpDriver) && 221 DriverConfig->EvtDriverDeviceAdd != NULL) { 222 223 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, 224 "Invalid Driver flags or EvtDriverDeviceAdd callback already added" 225 "STATUS_INVALID_PARAMETER"); 226 227 return STATUS_INVALID_PARAMETER; 228 } 229 230 status = FxValidateObjectAttributes(pFxDriverGlobals, DriverAttributes, 231 (FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED | 232 FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED | 233 FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED) 234 ); 235 236 if (!NT_SUCCESS(status)) { 237 return status; 238 } 239 240 // 241 // FxDriver stores the driver wide configuration 242 // 243 FxInitialize(pFxDriverGlobals, DriverObject, RegistryPath, DriverConfig); 244 245 // 246 // FxDriver stores the driver wide configuration 247 // 248 pDriver = new(pFxDriverGlobals, DriverAttributes) 249 FxDriver(DriverObject, DriverConfig, pFxDriverGlobals); 250 251 if (pDriver != NULL) { 252 253 if (NT_SUCCESS(status)) { 254 255 status = pDriver->Initialize(RegistryPath, DriverConfig, DriverAttributes); 256 257 if (NT_SUCCESS(status)) { 258 status = pDriver->Commit(DriverAttributes, (WDFOBJECT*)&hDriver, FALSE); 259 } 260 } 261 } 262 else { 263 status = STATUS_INSUFFICIENT_RESOURCES; 264 } 265 266 // 267 // Only return a valid handle on success. Upon error, release any memory 268 // and do not rely on any other function (like the driver unload routine) to 269 // be called. 270 // 271 if (NT_SUCCESS(status)) { 272 // 273 // **** Note **** 274 // Do not introduce failures after this point without ensuring 275 // FxObject::DeleteFromFailedCreate has a chance to clear out any 276 // assigned callbacks on the object. 277 // 278 279 // 280 // Store the WDFDRIVER and FxDriver* globally so the driver can retrieve 281 // it anytime. 282 // 283 pFxDriverGlobals->Driver = pDriver; 284 pFxDriverGlobals->Public.Driver = hDriver; 285 286 // 287 // Record the flags so that diagnostics knows what type of driver it is. 288 // 289 pFxDriverGlobals->Public.DriverFlags |= DriverConfig->DriverInitFlags; 290 291 if (DriverConfig->DriverInitFlags & 292 (WdfDriverInitNoDispatchOverride | WdfDriverInitNonPnpDriver)) { 293 // 294 // If there is no dispatch override or if it is an NT4 legacy style 295 // driver then we will not displace unload in the stub if one was not 296 // specified. 297 // 298 if (DriverConfig->EvtDriverUnload != NULL) { 299 pFxDriverGlobals->Public.DisplaceDriverUnload = TRUE; 300 } 301 else { 302 pFxDriverGlobals->Public.DisplaceDriverUnload = FALSE; 303 } 304 } 305 else { 306 pFxDriverGlobals->Public.DisplaceDriverUnload = TRUE; 307 } 308 309 if (Driver != NULL) { 310 *Driver = hDriver; 311 } 312 313 #ifndef __REACTOS__ 314 if (FX_TELEMETRY_ENABLED(g_TelemetryProvider, pFxDriverGlobals)) { 315 FxAutoString imageName; 316 317 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 318 const PWCHAR pVersionStr = 319 FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"." 320 FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"." 321 FX_MAKE_WSTR(__WDF_BUILD_NUMBER) ; 322 #else // USER_MODE 323 const PWCHAR pVersionStr = 324 FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"." 325 FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"." 326 FX_MAKE_WSTR(__WUDF_SERVICE_VERSION) ; 327 #endif 328 329 // 330 // GetImageName can fail if the registry cannot be accessed. This 331 // can happen during system shutdown. Since the image name is only 332 // used for telemetry the failure can be ignored. 333 // 334 (VOID) GetImageName(pFxDriverGlobals, &imageName.m_UnicodeString); 335 336 WDF_CENSUS_EVT_WRITE_DRIVER_LOAD(g_TelemetryProvider, 337 pFxDriverGlobals, 338 imageName.m_UnicodeString.Buffer, 339 pVersionStr); 340 } 341 #endif // __REACTOS__ 342 } 343 else { 344 if (pDriver != NULL) { 345 pDriver->DeleteFromFailedCreate(); 346 } 347 348 FxDestroy(pFxDriverGlobals); 349 } 350 351 return status; 352 } 353 354 _Must_inspect_result_ 355 __drv_maxIRQL(PASSIVE_LEVEL) 356 NTSTATUS 357 STDCALL 358 WDFEXPORT(WdfDriverRegisterTraceInfo)( 359 __in 360 PWDF_DRIVER_GLOBALS DriverGlobals, 361 __in 362 PDRIVER_OBJECT DriverObject, 363 __in 364 PFN_WDF_TRACE_CALLBACK EvtTraceCallback, 365 __in 366 PVOID ControlBlock 367 ) 368 { 369 DDI_ENTRY(); 370 371 UNREFERENCED_PARAMETER(DriverGlobals); 372 UNREFERENCED_PARAMETER(DriverObject); 373 UNREFERENCED_PARAMETER(EvtTraceCallback); 374 UNREFERENCED_PARAMETER(ControlBlock); 375 376 return STATUS_NOT_SUPPORTED; 377 } 378 379 _Must_inspect_result_ 380 __drv_maxIRQL(PASSIVE_LEVEL) 381 NTSTATUS 382 STDCALL 383 WDFEXPORT(WdfDriverRetrieveVersionString)( 384 __in 385 PWDF_DRIVER_GLOBALS DriverGlobals, 386 __in 387 WDFDRIVER Driver, 388 __in 389 WDFSTRING String 390 ) 391 { 392 DDI_ENTRY(); 393 394 PFX_DRIVER_GLOBALS pFxDriverGlobals; 395 FxDriver* pDriver; 396 FxString* pString; 397 NTSTATUS status; 398 399 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 400 const PWCHAR pVersionStr = 401 L"Kernel Mode Driver Framework version " 402 FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"." 403 FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"." 404 FX_MAKE_WSTR(__WDF_BUILD_NUMBER) ; 405 406 const PWCHAR pVersionStrVerifier = 407 L"Kernel Mode Driver Framework (verifier on) version " 408 FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"." 409 FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"." 410 FX_MAKE_WSTR(__WDF_BUILD_NUMBER); 411 #else // USER_MODE 412 const PWCHAR pVersionStr = 413 L"User Mode Driver Framework version " 414 FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"." 415 FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"." 416 FX_MAKE_WSTR(__WUDF_SERVICE_VERSION) ; 417 418 const PWCHAR pVersionStrVerifier = 419 L"User Mode Driver Framework (verifier on) version " 420 FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"." 421 FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"." 422 FX_MAKE_WSTR(__WUDF_SERVICE_VERSION); 423 #endif 424 425 // 426 // Even though it is unused, still convert it to make sure a valid handle is 427 // being passed in. 428 // 429 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 430 Driver, 431 FX_TYPE_DRIVER, 432 (PVOID *)&pDriver, 433 &pFxDriverGlobals); 434 435 FxPointerNotNull(pFxDriverGlobals, String); 436 437 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 438 if (!NT_SUCCESS(status)) { 439 return status; 440 } 441 442 FxObjectHandleGetPtr(pFxDriverGlobals, 443 String, 444 FX_TYPE_STRING, 445 (PVOID *)&pString); 446 447 status = pString->Assign( 448 pFxDriverGlobals->FxVerifierOn ? pVersionStrVerifier : pVersionStr 449 ); 450 451 return status; 452 } 453 454 _Must_inspect_result_ 455 __drv_maxIRQL(PASSIVE_LEVEL) 456 BOOLEAN 457 STDCALL 458 WDFEXPORT(WdfDriverIsVersionAvailable)( 459 __in 460 PWDF_DRIVER_GLOBALS DriverGlobals, 461 __in 462 WDFDRIVER Driver, 463 __in 464 PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams 465 ) 466 { 467 DDI_ENTRY(); 468 469 PFX_DRIVER_GLOBALS pFxDriverGlobals; 470 FxDriver* pDriver; 471 NTSTATUS status; 472 ULONG major, minor; 473 474 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) 475 major = __WDF_MAJOR_VERSION; 476 minor = __WDF_MINOR_VERSION; 477 #else 478 major = __WUDF_MAJOR_VERSION; 479 minor = __WUDF_MINOR_VERSION; 480 #endif 481 482 // 483 // Even though it is unused, still convert it to make sure a valid handle is 484 // being passed in. 485 // 486 FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), 487 Driver, 488 FX_TYPE_DRIVER, 489 (PVOID *)&pDriver, 490 &pFxDriverGlobals); 491 492 FxPointerNotNull(pFxDriverGlobals, VersionAvailableParams); 493 494 status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); 495 if (!NT_SUCCESS(status)) { 496 return FALSE; 497 } 498 499 if (VersionAvailableParams->Size != sizeof(WDF_DRIVER_VERSION_AVAILABLE_PARAMS)) { 500 status = STATUS_INFO_LENGTH_MISMATCH; 501 502 DoTraceLevelMessage( 503 pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, 504 "VersionAvailableParams Size 0x%x, expected 0x%x, %!STATUS!", 505 VersionAvailableParams->Size, sizeof(WDF_DRIVER_VERSION_AVAILABLE_PARAMS), 506 status); 507 508 return FALSE; 509 } 510 511 // 512 // We log at TRACE_LEVEL_INFORMATION so that we know it gets into the IFR at 513 // all times. This will make it easier to debug drivers which fail to load 514 // when a new minor version of WDF is installed b/c they are failing 515 // version checks. 516 // 517 DoTraceLevelMessage( 518 pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, 519 "IsVersionAvailable, current WDF ver major %d, minor %d, caller asking " 520 "about major %d, minor %d", major, minor, 521 VersionAvailableParams->MajorVersion, VersionAvailableParams->MinorVersion); 522 523 // 524 // Currently we only support one major version per KMDF binary and we support 525 // all minor versions of that major version down to 0x0. 526 // 527 if (VersionAvailableParams->MajorVersion == major && 528 VersionAvailableParams->MinorVersion <= minor) { 529 return TRUE; 530 } 531 532 return FALSE; 533 } 534 535 } // extern "C" 536