1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxPkgIo.hpp
8 
9 Abstract:
10 
11     This module implements the I/O package for the driver frameworks.
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19     Both kernel and user mode
20 
21 Revision History:
22 
23 --*/
24 
25 #ifndef _FXPKGIO_H_
26 #define _FXPKGIO_H_
27 
28 
29 
30 
31 #include "fxpkgioshared.hpp"
32 #include "fxirpdynamicdispatchinfo.hpp"
33 #include "fxdevicecallbacks.hpp"
34 #include "fxcxdeviceinfo.hpp"
35 
36 //
37 // This flag is or-ed with a pointer value that is ptr aligned, only lower 2 bits are available.
38 //
39 #define FX_IN_DISPATCH_CALLBACK     0x00000001
40 
41 enum FxIoIteratorList {
42     FxIoQueueIteratorListInvalid = 0,
43     FxIoQueueIteratorListPowerOn,
44     FxIoQueueIteratorListPowerOff,
45 };
46 
47 #define IO_ITERATOR_FLUSH_TAG (PVOID) 'sulf'
48 #define IO_ITERATOR_POWER_TAG (PVOID) 'ewop'
49 
50 //
51 // This class is allocated by the driver frameworks manager
52 // PER DEVICE, and is not package global, but per device global,
53 // data.
54 //
55 // This is similar to the NT DeviceExtension.
56 //
57 class FxPkgIo : public FxPackage
58 {
59 
60 private:
61 
62     FxIoQueue*  m_DefaultQueue;
63 
64     //
65     // This is the list of IoQueue objects allocated by the driver
66     // and associated with this device. The IoPackage instance
67     // will release these references automatically when the device
68     // is removed.
69     //
70     LIST_ENTRY  m_IoQueueListHead;
71 
72     //
73     // This is the forwarding table
74     //
75     FxIoQueue*  m_DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
76 
77     //
78     // This is the seed value used to pass to the
79     // FxRandom for testing forward progress
80     //
81     ULONG       m_RandomSeed;
82 
83     // TRUE if behave as a filter (forward default requests)
84     BOOLEAN     m_Filter;
85 
86     BOOLEAN     m_PowerStateOn;
87 
88     //
89     // TRUE if queues are shutting down (surprise_remove/remove in progress).
90     //
91     BOOLEAN     m_QueuesAreShuttingDown;
92 
93     //
94     // We'll maintain the dynamic dispatch table "per device" so that it is possible
95     // to have different callbacks for each device.
96     // Note that each device may be associted with multiple class extension in the future.
97     //
98     LIST_ENTRY  m_DynamicDispatchInfoListHead;
99 
100     //
101     // If !=NULL, a pre-process callback was registered
102     //
103     FxIoInCallerContext m_InCallerContextCallback;
104 
105 public:
106 
107     FxPkgIo(
108         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
109         __in CfxDevice *Device
110         );
111 
112     ~FxPkgIo();
113 
114     //
115     // Package manager dispatch entries
116     //
117     _Must_inspect_result_
118     virtual
119     NTSTATUS
120     Dispatch(
121         __inout MdIrp Irp
122         );
123 
124     //
125     // Returns the Top level queue for the Io based on the Irp MajorFunction
126     //
127     FxIoQueue*
GetDispatchQueue(_In_ UCHAR MajorFunction)128     GetDispatchQueue(
129         _In_ UCHAR MajorFunction
130         )
131     {
132         return m_DispatchTable[MajorFunction];
133     }
134 
135     // Do not specify argument names
136     FX_DECLARE_VF_FUNCTION_P1(
137     NTSTATUS,
138     VerifyDispatchContext,
139         _In_ WDFCONTEXT
140         );
141 
142     //
143     // Api's supplied by this package
144     //
145     _Must_inspect_result_
146     NTSTATUS
147     __fastcall
148     DispatchStep1(
149         __inout MdIrp        Irp,
150         __in    WDFCONTEXT  DispatchContext
151         );
152 
153     _Must_inspect_result_
154     NTSTATUS
155     __fastcall
156     DispatchStep2(
157         __inout  MdIrp        Irp,
158         __in_opt FxIoInCallerContext* IoInCallerCtx,
159         __in_opt FxIoQueue*  Queue
160         );
161 
162 /*++
163 
164     Routine Description:
165 
166     Initializes the default queue, and allows the driver to
167     pass configuration information.
168 
169     The driver callbacks registered in this call are used
170     to supply the callbacks for the driver default I/O queue.
171 
172 Arguments:
173 
174     hDevice - Pointer Device Object
175 
176 Return Value:
177 
178     NTSTATUS
179 
180 --*/
181     _Must_inspect_result_
182     NTSTATUS
183     InitializeDefaultQueue(
184         __in    CfxDevice               * Device,
185         __inout FxIoQueue               * Queue
186         );
187 
188     //
189     // Register the I/O in-caller context callback
190     //
191     __inline
192     VOID
SetIoInCallerContextCallback(__inout PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext)193     SetIoInCallerContextCallback(
194         __inout PFN_WDF_IO_IN_CALLER_CONTEXT       EvtIoInCallerContext
195         )
196     {
197         m_InCallerContextCallback.m_Method = EvtIoInCallerContext;
198     }
199 
200     // Do not specify argument names
201     FX_DECLARE_VF_FUNCTION_P2(
202     NTSTATUS,
203     VerifyEnqueueRequestUpdateFlags,
204         _In_ FxRequest*,
205         _Inout_ SHORT*
206         );
207 
208     // Do not specify argument names
209     FX_DECLARE_VF_FUNCTION_P2(
210     VOID,
211     VerifyEnqueueRequestRestoreFlags,
212         _In_ FxRequest*,
213         _In_ SHORT
214         );
215 
216     //
217     // Enqueue a request to the I/O processing pipeline
218     // from the device driver
219     //
220     _Must_inspect_result_
221     NTSTATUS
222     EnqueueRequest(
223         __in    CfxDevice* Device,
224         __inout FxRequest* pRequest
225         );
226 
227     FxDriver*
228     GetDriver(
229         VOID
230         );
231 
232     __inline
233     CfxDevice*
GetDevice(VOID)234     GetDevice(
235         VOID
236         )
237     {
238         return m_Device;
239     }
240 
241     __inline
242     FxIoQueue*
GetDefaultQueue(VOID)243     GetDefaultQueue(
244         VOID
245         )
246     {
247         return m_DefaultQueue;
248     }
249 
250     __inline
251     BOOLEAN
IsFilter(VOID)252     IsFilter(
253         VOID
254         )
255     {
256         return m_Filter;
257     }
258 
259     //
260     // This is called as a result of a power management state
261     // that requests that all I/O in progress stop.
262     //
263     //
264     // FxIoStopProcessingForPowerHold:
265     // the function returns when the driver has acknowledged that it has
266     // stopped all I/O processing, but may have outstanding "in-flight" requests
267     // that have not been completed.
268     //
269     // FxIoStopProcessingForPowerPurge:
270     // the function returns when all requests have been completed and/or
271     // cancelled., and there are no more in-flight requests.
272     //
273     // Any queues not marked as PowerManaged will be left alone.
274     //
275     // This is called on a PASSIVE_LEVEL thread that can block until
276     // I/O has been stopped, or completed/cancelled.
277     //
278     _Must_inspect_result_
279     NTSTATUS
280     StopProcessingForPower(
281         __in FxIoStopProcessingForPowerAction Action
282         );
283 
284     //
285     // This is called to start, or resume processing when PNP/Power
286     // resources have been supplied to the device driver.
287     //
288     // The driver is notified of resumption for any in-flight I/O.
289     //
290     _Must_inspect_result_
291     NTSTATUS
292     ResumeProcessingForPower();
293 
294     //
295     // This is called on a device which has been restarted from the removed
296     // state.  It will reset purged queues so that they can accept new requests
297     // when ResumeProcessingForPower is called afterwards.
298     //
299     VOID
300     ResetStateForRestart(
301         VOID
302         );
303 
304     //
305     // Called by CfxDevice when WdfDeviceSetFilter is called.
306     //
307     _Must_inspect_result_
308     NTSTATUS
309     SetFilter(
310         __in BOOLEAN Value
311         );
312 
313     //
314     // Create an IoQueue and associate it with the FxIoPkg per device
315     // instance.
316     //
317     _Must_inspect_result_
318     NTSTATUS
319     CreateQueue(
320         __in  PWDF_IO_QUEUE_CONFIG     Config,
321         __in  PWDF_OBJECT_ATTRIBUTES   QueueAttributes,
322         __in_opt FxDriver*             Caller,
323         __deref_out FxIoQueue**        ppQueue
324         );
325 
326     VOID
327     RemoveQueueReferences(
328         __inout FxIoQueue* pQueue
329         );
330 
331     _Must_inspect_result_
332     NTSTATUS
333     ConfigureDynamicDispatching(
334         __in UCHAR               MajorFunction,
335         __in_opt FxCxDeviceInfo* CxDeviceInfo,
336         __in PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDispatch,
337         __in_opt WDFCONTEXT      DriverContext
338         );
339 
340     _Must_inspect_result_
341     NTSTATUS
342     ConfigureForwarding(
343         __inout FxIoQueue* TargetQueue,
344         __in    WDF_REQUEST_TYPE RequestType
345         );
346 
347     _Must_inspect_result_
348     NTSTATUS
349     FlushAllQueuesByFileObject(
350         __in MdFileObject FileObject
351         );
352 
353     __inline
354     VOID
RequestCompletedCallback(__in FxRequest * Request)355     RequestCompletedCallback(
356         __in FxRequest* Request
357         )
358     {
359         UNREFERENCED_PARAMETER(Request);
360 
361         //
362         // If this is called, the driver called WDFREQUEST.Complete
363         // from the PreProcess callback handler.
364         //
365         // Since we have a handler, the FXREQUEST object will
366         // dereference itself upon return from this callback, which
367         // will destroy the final reference count.
368         //
369     }
370 
371     __inline
372     BOOLEAN
IsTopLevelQueue(__in FxIoQueue * Queue)373     IsTopLevelQueue(
374         __in FxIoQueue* Queue
375         )
376     {
377         UCHAR index;
378 
379         for (index = 0; index <= IRP_MJ_MAXIMUM_FUNCTION; index++) {
380           if (m_DispatchTable[index] == Queue) {
381               return TRUE;
382           }
383         }
384         return FALSE;
385     }
386 
387     NTSTATUS
388     DispathToInCallerContextCallback(
389         __in    FxIoInCallerContext *InCallerContextInfo,
390         __in    FxRequest *Request,
391         __inout MdIrp      Irp
392         );
393 
394     __inline
395     FxIoInCallerContext*
GetIoInCallerContextCallback(__in_opt FxCxDeviceInfo * CxDeviceInfo)396     GetIoInCallerContextCallback(
397         __in_opt FxCxDeviceInfo* CxDeviceInfo
398         )
399     {
400         if (CxDeviceInfo != NULL) {
401             return &CxDeviceInfo->IoInCallerContextCallback;
402         }
403         else {
404             return &m_InCallerContextCallback;
405         }
406     }
407 
408 private:
409 
410     VOID
411     AddIoQueue(
412         __inout FxIoQueue* IoQueue
413         );
414 
415     VOID
416     RemoveIoQueue(
417         __inout FxIoQueue* IoQueue
418         );
419 
420     FxIoQueue*
421     GetFirstIoQueueLocked(
422         __in FxIoQueueNode* QueueBookmark,
423         __in PVOID Tag
424         );
425 
426     FxIoQueue*
427     GetNextIoQueueLocked(
428         __in FxIoQueueNode* QueueBookmark,
429         __in PVOID Tag
430         );
431 
432     VOID
433     GetIoQueueListLocked(
434         __in    PSINGLE_LIST_ENTRY SListHead,
435         __inout FxIoIteratorList ListType
436         );
437 
438     _Must_inspect_result_
439     NTSTATUS
440     VerifierFreeRequestToTestForwardProgess(
441         __in FxRequest* Request
442         );
443 
444 };
445 
446 #endif // _FXPKGIO_H
447