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
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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