1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxDriver.cpp
8 
9 Abstract:
10 
11     This is the main driver framework.
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 #include "fxiotarget.hpp"
27 
28 // Tracing support
29 extern "C" {
30 // #include "FxDriver.tmh"
31 }
32 
33 FxDriver::FxDriver(
34     __in MdDriverObject     ArgDriverObject,
35     __in PWDF_DRIVER_CONFIG DriverConfig,
36     __in PFX_DRIVER_GLOBALS FxDriverGlobals
37     ) :
38     FxNonPagedObject(FX_TYPE_DRIVER, sizeof(FxDriver), FxDriverGlobals),
39     m_DriverObject(ArgDriverObject),
40     m_CallbackMutexLock(FxDriverGlobals)
41 {
42     RtlInitUnicodeString(&m_RegistryPath, NULL);
43 
44 
45 
46 
47 
48 
49 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
50     m_ExecutionLevel = WdfExecutionLevelDispatch;
51 #else
52     m_ExecutionLevel = WdfExecutionLevelPassive;
53 #endif
54 
55     m_SynchronizationScope = WdfSynchronizationScopeNone;
56 
57     m_CallbackLockPtr = NULL;
58     m_CallbackLockObjectPtr = NULL;
59 
60     m_DisposeList = NULL;
61 
62     //
63     // These are initialized up front so that sub objects
64     // can have the right configuration
65     //
66     WDF_DRIVER_CONFIG_INIT(&m_Config, NULL);
67 
68     // Only copy the smallest of what is specified and our size
69     RtlCopyMemory(&m_Config, DriverConfig, min(sizeof(m_Config), DriverConfig->Size) );
70 
71     m_DebuggerConnected = FALSE;
72 
73 #if FX_IS_USER_MODE
74     m_DriverParametersKey = NULL;
75 #endif
76 }
77 
78 FxDriver::~FxDriver()
79 {
80     // Make it always present right now even on free builds
81     if (IsDisposed() == FALSE) {
82         DoTraceLevelMessage(
83             GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGDRIVER,
84             "FxDriver 0x%p not disposed: this maybe a driver reference count "
85             "problem with WDFDRIVER 0x%p", this, GetObjectHandleUnchecked());
86 
87         FxVerifierBugCheck(GetDriverGlobals(),
88                            WDF_OBJECT_ERROR,
89                            (ULONG_PTR) GetObjectHandleUnchecked(),
90                            (ULONG_PTR) this);
91     }
92 
93     //
94     // Free the memory for the registry path if required.
95     //
96     if (m_RegistryPath.Buffer) {
97         FxPoolFree(m_RegistryPath.Buffer);
98     }
99 
100     if (m_DisposeList != NULL) {
101         m_DisposeList->DeleteObject();
102     }
103 
104 #if FX_IS_USER_MODE
105     //
106     // Close the R/W handle to the driver's service parameters key
107     // that we opened during Initialize.
108     //
109     if (m_DriverParametersKey != NULL) {
110         NTSTATUS status = FxRegKey::_Close(m_DriverParametersKey);
111         if (!NT_SUCCESS(status)) {
112             DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDRIVER,
113                                 "Cannot close Driver Parameters key %!STATUS!",
114                                 status);
115         }
116         m_DriverParametersKey = NULL;
117     }
118 
119     //
120     // The host-created driver object holds a reference to this
121     // FxDriver object. Clear it, since this object was deleted.
122     //
123     ClearDriverObjectFxDriver();
124 #endif
125 }
126 
127 BOOLEAN
128 FxDriver::Dispose(
129     VOID
130     )
131 {
132     if (m_DisposeList != NULL) {
133         m_DisposeList->WaitForEmpty();
134     }
135 
136     return FxNonPagedObject::Dispose(); // __super call
137 }
138 
139 VOID
140 FxDriver::Unload(
141     __in MdDriverObject DriverObject
142     )
143 {
144     PFX_DRIVER_GLOBALS pFxDriverGlobals;
145     FxDriver *pDriver;
146 
147     pDriver = FxDriver::GetFxDriver(DriverObject);
148     if (pDriver == NULL) {
149         return;
150     }
151 
152     pFxDriverGlobals = pDriver->GetDriverGlobals();
153 
154     DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
155                         "Unloading WDFDRIVER %p, PDRIVER_OBJECT_UM %p",
156                         pDriver->GetHandle(), DriverObject);
157     //
158     // Invoke the driver if they specified an unload routine.
159     //
160     if (pDriver->m_DriverUnload.Method) {
161         pDriver->m_DriverUnload.Invoke(pDriver->GetHandle());
162         DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER,
163                             "Driver unload routine Exit WDFDRIVER %p, PDRIVER_OBJECT_UM %p",
164                             pDriver->GetHandle(), DriverObject);
165     }
166 
167     //
168     // Delete the FxDriver object.
169     //
170     // This releases the FxDriver reference.  Must be called at PASSIVE
171     //
172     pDriver->DeleteObject();
173 
174     pFxDriverGlobals->Driver = NULL;
175 
176     FxDestroy(pFxDriverGlobals);
177 }
178 
179 VOID
180 FxDriver::_InitializeDriverName(
181     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
182     __in PCUNICODE_STRING RegistryPath
183     )
184 /*++
185 
186 Routine Description:
187     Create a CHAR version of the service name contained in RegistryPath.
188 
189 Arguments:
190     RegistryPath - the path to the service name in the registry.
191 
192 Return Value:
193     None
194 
195   --*/
196 {
197     PWCHAR pCur, pBegin, pEnd;
198 
199     RtlZeroMemory(&FxDriverGlobals->Public.DriverName[0],
200                   sizeof(FxDriverGlobals->Public.DriverName) );
201 
202     if (RegistryPath == NULL) {
203         return;
204     }
205 
206     pBegin = RegistryPath->Buffer;
207 
208     //
209     // pEnd is one past the end of the string, while pCur is a pointer to the
210     // last character of the string.  We will decrement pCur down towards the
211     // beginning of the string.
212     //
213     pEnd = pBegin + (RegistryPath->Length / sizeof(WCHAR));
214     pCur = pEnd - 1;
215 
216     for ( ; *pCur != L'\\' && pCur != pBegin; pCur--) {
217         DO_NOTHING();
218     }
219 
220     if (pCur != pBegin && *pCur == L'\\') {
221         size_t regLen;
222         ULONG i;
223 
224         pCur++;
225 
226         //
227         // Can't use wcslen becuase this is a UNICODE_STRING which means that it
228         // does not necessarily have a terminating NULL in the buffer.
229         //
230         regLen = pEnd - pCur;
231         if (regLen > WDF_DRIVER_GLOBALS_NAME_LEN-1) {
232             regLen = WDF_DRIVER_GLOBALS_NAME_LEN-1;
233         }
234 
235 
236         for (i = 0; i < regLen; i++) {
237             FxDriverGlobals->Public.DriverName[i] = (CHAR) pCur[i];
238         }
239     }
240     else {
241         NTSTATUS status;
242 
243 #if FX_CORE_MODE==FX_CORE_KERNEL_MODE
244         status = RtlStringCbCopyA(FxDriverGlobals->Public.DriverName,
245                                   sizeof(FxDriverGlobals->Public.DriverName),
246                                   "WDF");
247 #else // USER_MODE
248         HRESULT hr;
249         hr = StringCbCopyA(FxDriverGlobals->Public.DriverName,
250                            sizeof(FxDriverGlobals->Public.DriverName),
251                            "WDF");
252         if (HRESULT_FACILITY(hr) == FACILITY_WIN32) {
253             status = WinErrorToNtStatus(HRESULT_CODE(hr));
254         }
255         else {
256             status = SUCCEEDED(hr) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
257         }
258 #endif
259 
260         UNREFERENCED_PARAMETER(status);
261         ASSERT(NT_SUCCESS(status));
262     }
263 }
264 
265 VOID
266 FxDriver::_InitializeTag(
267     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
268     __in PWDF_DRIVER_CONFIG Config
269     )
270 /*++
271 
272 Routine Description:
273     Tries to create a tag for the driver based off of its name.  This tag is
274     used for allocations made on behalf of the driver so that it is easier to
275     track which allocations belong to which image.
276 
277 Arguments:
278     Config - driver writer provided config.  in the future, may contain a tag
279              value in it
280 
281 Return Value:
282     None
283 
284   --*/
285 {
286     PCHAR  pBegin;
287     size_t length;
288 
289     UNREFERENCED_PARAMETER(Config);
290 
291     length = strlen(FxDriverGlobals->Public.DriverName);
292     pBegin = &FxDriverGlobals->Public.DriverName[0];
293 
294     if (length >= 3) {
295         //
296         // If the driver name begins with "WDF" (case insensitive), start after
297         // "WDF"
298         //
299         if ((pBegin[0] == 'w' || pBegin[0] == 'W') &&
300             (pBegin[1] == 'd' || pBegin[1] == 'D') &&
301             (pBegin[2] == 'f' || pBegin[2] == 'F')) {
302             length -=3;
303             pBegin += 3;
304         }
305     }
306 
307     if (length <= 2) {
308         //
309         // 2 or less characters is not a unique enough tag, just use the default
310         // tag.
311         //
312         FxDriverGlobals->Tag = FX_TAG;
313     }
314     else {
315 
316         if (length > sizeof(ULONG)) {
317             length = sizeof(ULONG);
318         }
319 
320         //
321         // This copies the bytes in the right order (so that they appear correct
322         // when dumped as a sequence of chars)
323         //
324         RtlCopyMemory(&FxDriverGlobals->Tag,
325                       pBegin,
326                       length);
327 
328         FxDriverGlobals->Public.DriverTag = FxDriverGlobals->Tag;
329     }
330 }
331 
332 _Must_inspect_result_
333 NTSTATUS
334 FxDriver::Initialize(
335     __in PCUNICODE_STRING ArgRegistryPath,
336     __in PWDF_DRIVER_CONFIG Config,
337     __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes
338     )
339 {
340     PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals();
341     NTSTATUS status;
342 
343     // WDFDRIVER can not be deleted by the device driver
344     MarkNoDeleteDDI();
345 
346     MarkDisposeOverride(ObjectDoNotLock);
347 
348     //
349     // Configure Constraints
350     //
351     ConfigureConstraints(DriverAttributes);
352 
353     if (m_DriverObject.GetObject() == NULL) {
354         return STATUS_UNSUCCESSFUL;
355     }
356 
357     // Allocate FxDisposeList
358     status = FxDisposeList::_Create(FxDriverGlobals, m_DriverObject.GetObject(), &m_DisposeList);
359     if (!NT_SUCCESS(status)) {
360         return status;
361     }
362 
363     //
364     // Store FxDriver in Driver object extension
365     //
366     status = AllocateDriverObjectExtensionAndStoreFxDriver();
367     if (!NT_SUCCESS(status)) {
368         return status;
369     }
370 
371     //
372     // Store away the callback functions.
373     //
374     if ((Config->DriverInitFlags & WdfDriverInitNoDispatchOverride) == 0) {
375         //
376         // Caller doesn't want to override the dispatch table.  That
377         // means that they want to create everything and still be in
378         // control (or at least the port driver will take over)
379         //
380         m_DriverDeviceAdd.Method  = Config->EvtDriverDeviceAdd;
381         m_DriverUnload.Method     = Config->EvtDriverUnload;
382     }
383 
384     if (ArgRegistryPath != NULL) {
385         USHORT length;
386 
387         length = ArgRegistryPath->Length + sizeof(UNICODE_NULL);
388 
389         m_RegistryPath.Length = ArgRegistryPath->Length;
390         m_RegistryPath.MaximumLength = length;
391         m_RegistryPath.Buffer = (PWSTR) FxPoolAllocate(
392             GetDriverGlobals(), PagedPool, length);
393 
394         if (m_RegistryPath.Buffer != NULL) {
395             RtlCopyMemory(m_RegistryPath.Buffer,
396                           ArgRegistryPath->Buffer,
397                           ArgRegistryPath->Length);
398 
399             //
400             // other parts of WDF assumes m_RegistryPath.Buffer is
401             // a null terminated string.  make sure it is.
402             //
403             m_RegistryPath.Buffer[length/sizeof(WCHAR)- 1] = UNICODE_NULL;
404         }
405         else {
406             //
407             // We failed to allocate space for the registry path
408             // so set the length to 0.
409             //
410             m_RegistryPath.Length = 0;
411             m_RegistryPath.MaximumLength = 0;
412 
413             status = STATUS_INSUFFICIENT_RESOURCES;
414         }
415     }
416 
417     if (NT_SUCCESS(status)) {
418         if ((Config->DriverInitFlags & WdfDriverInitNoDispatchOverride) == 0) {
419             UCHAR i;
420 
421             //
422             // Set up dispatch routines.
423             //
424             if (Config->DriverInitFlags & WdfDriverInitNonPnpDriver) {
425                 //
426                 // NT4 style drivers must clear the AddDevice field in the
427                 // driver object so that they can be unloaded while still
428                 // having device objects around.
429                 //
430                 // If AddDevice is set, NT considers the driver a pnp driver
431                 // and will not allow net stop to unload the driver.
432                 //
433                 m_DriverObject.SetDriverExtensionAddDevice(NULL);
434 
435                 //
436                 // Unload for an NT4 driver is still optional if the driver
437                 // does not want to be stopped (through net stop for
438                 // instance).
439                 //
440                 if (Config->EvtDriverUnload != NULL) {
441                     m_DriverObject.SetDriverUnload(Unload);
442                 }
443                 else {
444                     m_DriverObject.SetDriverUnload(NULL);
445                 }
446 
447             }
448             else {
449                 //
450                 // PnP driver, set our routines up
451                 //
452                 m_DriverObject.SetDriverExtensionAddDevice(AddDevice);
453                 m_DriverObject.SetDriverUnload(Unload);
454             }
455 
456             //
457             // For any major control code that we use a remove lock, the
458             // following locations must be updated:
459             //
460             // 1)  FxDevice::_RequiresRemLock() which decides if the remlock
461             //          is required
462             // 2)  FxDefaultIrpHandler::Dispatch might need to be changed if
463             //          there is catchall generic post processing that must be done
464             // 3)  Whereever the major code irp handler completes the irp or
465             //          sends it down the stack.  A good design would have all
466             //          spots in the irp handler where this is done to call a
467             //          common function.
468             //
469             WDFCASSERT(IRP_MN_REMOVE_DEVICE != 0x0);
470 
471 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
472             for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
473                 if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) {
474                     m_DriverObject.SetMajorFunction(i, FxDevice::Dispatch);
475                 }
476                 else {
477                     m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLock);
478                 }
479             }
480 #else // USER_MODE
481             for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
482                 if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) {
483                     m_DriverObject.SetMajorFunction(i, FxDevice::DispatchUm);
484                 }
485                 else {
486                     m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLockUm);
487                 }
488             }
489 #endif
490         }
491 
492         //
493         // Determine if the debugger is connected.
494         //
495 #if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE))
496         if (KD_DEBUGGER_ENABLED == TRUE && KD_DEBUGGER_NOT_PRESENT == FALSE) {
497             m_DebuggerConnected = TRUE;
498         }
499 #endif
500 
501         //
502         // Log this notable event after tracing has been initialized.
503         //
504 
505 
506 
507 
508 
509 
510         if ((Config->DriverInitFlags & WdfDriverInitNonPnpDriver) &&
511             Config->EvtDriverUnload == NULL) {
512 
513             DoTraceLevelMessage(
514                 FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER,
515                 "Driver Object %p, reg path %wZ cannot be "
516                 "unloaded, no DriverUnload routine specified",
517                 m_DriverObject.GetObject(), &m_RegistryPath);
518         }
519 
520 #if FX_IS_USER_MODE
521         //
522         // Open a R/W handle to the driver's service parameters key
523         //
524         status = OpenParametersKey();
525         if (!NT_SUCCESS(status)) {
526             DoTraceLevelMessage(
527                 FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER,
528                 "Cannot open Driver Parameters key %!STATUS!",
529                 status);
530         }
531 #endif
532     }
533 
534     return status;
535 }
536 
537 _Must_inspect_result_
538 FxString *
539 FxDriver::GetRegistryPath(
540     VOID
541     )
542 {
543     FxString *pString;
544 
545     pString = new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES)
546         FxString(GetDriverGlobals());
547 
548     if (pString != NULL) {
549         NTSTATUS status;
550 
551         status = pString->Assign(m_RegistryPath.Buffer);
552 
553         if (!NT_SUCCESS(status)) {
554             pString->Release();
555             pString = NULL;
556         }
557     }
558 
559     return pString;
560 }
561 
562 
563 VOID
564 FxDriver::ConfigureConstraints(
565     __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes
566     )
567 /*++
568 
569 Routine Description:
570 
571     Determine the pointer to the proper lock to acquire
572     for event callbacks from the FxDriver to the device driver
573     depending on the configured locking model.
574 
575 Arguments:
576     DriverAttributes - caller supplied scope and level, used only if they
577         are not InheritFromParent.
578 
579 Returns:
580     None
581 
582 --*/
583 {
584     BOOLEAN automaticLockingRequired;
585 
586     automaticLockingRequired = FALSE;
587 
588     // Initialize the mutex lock
589     m_CallbackMutexLock.Initialize(this);
590 
591 
592 
593 
594 
595 
596 
597 
598 
599     MarkPassiveCallbacks(ObjectDoNotLock);
600 
601     m_CallbackLockPtr = &m_CallbackMutexLock;
602     m_CallbackLockObjectPtr = this;
603 
604     //
605     // Use the caller supplied scope and level only if they are not
606     // InheritFromParent.
607     //
608     if (DriverAttributes != NULL) {
609 
610         if (DriverAttributes->ExecutionLevel !=
611                 WdfExecutionLevelInheritFromParent) {
612             m_ExecutionLevel = DriverAttributes->ExecutionLevel;
613         }
614 
615         if (DriverAttributes->SynchronizationScope !=
616                 WdfSynchronizationScopeInheritFromParent) {
617             m_SynchronizationScope = DriverAttributes->SynchronizationScope;
618         }
619     }
620 
621     //
622     // If the driver asks for any synchronization, we synchronize the
623     // WDFDRIVER object's own callbacks as well.
624     //
625     // (No option to extend synchronization for regular operations
626     //  across all WDFDEVICE objects)
627     //
628     if (m_SynchronizationScope == WdfSynchronizationScopeDevice ||
629         m_SynchronizationScope == WdfSynchronizationScopeQueue) {
630 
631         automaticLockingRequired = TRUE;
632     }
633 
634     //
635     // No FxDriver events are delivered from a thread that is
636     // not already at PASSIVE_LEVEL, so we don't need to
637     // allocate an FxSystemWorkItem if the execution level
638     // constraint is WdfExecutionLevelPassive.
639     //
640     // If any events are added FxDriver that could occur on a thread
641     // that is above PASSIVE_LEVEL, then an FxSystemWorkItem would
642     // need to be allocated to deliver those events similar to the
643     // code in FxIoQueue.
644     //
645 
646     //
647     // Configure FxDriver event callback locks
648     //
649     if (automaticLockingRequired) {
650         m_DriverDeviceAdd.SetCallbackLockPtr(m_CallbackLockPtr);
651     }
652     else {
653         m_DriverDeviceAdd.SetCallbackLockPtr(NULL);
654     }
655 }
656 
657