1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxResource.hpp
8 
9 Abstract:
10 
11     This module implements the resource object.
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19     Both kernel and user mode
20 
21 Revision History:
22 
23 --*/
24 
25 #ifndef _FXRESOURCE_H_
26 #define _FXRESOURCE_H_
27 
28 extern "C" {
29 
30 #if defined(EVENT_TRACING)
31 #include "FxResource.hpp.tmh"
32 #endif
33 
34 }
35 
36 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
37 
38 struct FxRegisterResourceInfo : FxStump {
39     //
40     // start physical address of resource range assigned by pnp
41     //
42     PHYSICAL_ADDRESS m_StartPa;
43 
44     //
45     // start of mapped system base address
46     //
47     PVOID m_StartSystemVa;
48 
49     //
50     // end of mapped system base address
51     //
52     PVOID m_EndSystemVa;
53 
54     //
55     // user-mode mapped address
56     //
57     PVOID m_StartUsermodeVa;
58 
59     //
60     // Length of resource range assigned by pnp
61     //
62     SIZE_T m_Length;
63 
64     //
65     // Length of mapped resource range
66     //
67     SIZE_T m_MappedLength;
68 
69     static
70     NTSTATUS
_CreateAndInitFxRegisterResourceInfo71     _CreateAndInit(
72         _In_ PFX_DRIVER_GLOBALS DriverGlobals,
73         _In_ ULONG Count,
74         _Out_ FxRegisterResourceInfo** RegisterTable
75         )
76     {
77         NTSTATUS status;
78         FxRegisterResourceInfo* table;
79 
80         ASSERT(RegisterTable != NULL);
81         *RegisterTable = NULL;
82 
83         table = new (DriverGlobals) FxRegisterResourceInfo[Count];
84         if (table == NULL) {
85             status = STATUS_INSUFFICIENT_RESOURCES;
86             DoTraceLevelMessage(
87                 DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
88                 "Failed to allocate Resource table %!STATUS!", status);
89             return status;
90         }
91 
92         *RegisterTable = table;
93         status = STATUS_SUCCESS;
94 
95         return status;
96     }
97 
FxRegisterResourceInfoFxRegisterResourceInfo98     FxRegisterResourceInfo(
99         VOID
100         ):
101         m_StartSystemVa(NULL),
102         m_EndSystemVa(NULL),
103         m_StartUsermodeVa(NULL),
104         m_Length(0),
105         m_MappedLength(0)
106     {
107         m_StartPa.QuadPart = 0;
108     };
109 
~FxRegisterResourceInfoFxRegisterResourceInfo110     ~FxRegisterResourceInfo(){;};
111 
112     VOID
SetPhysicalAddressFxRegisterResourceInfo113     SetPhysicalAddress(
114         __in PHYSICAL_ADDRESS StartPa,
115         __in SIZE_T Length
116         )
117     {
118         m_StartPa = StartPa;
119         m_Length = Length;
120     }
121 
122     VOID
SetMappedAddressFxRegisterResourceInfo123     SetMappedAddress(
124         __in PVOID SystemBaseAddress,
125         __in SIZE_T MappedLength,
126         __in PVOID UsermodeBaseAddress
127         )
128     {
129         m_StartSystemVa = SystemBaseAddress;
130         m_MappedLength = MappedLength;
131         m_EndSystemVa = ((PUCHAR) m_StartSystemVa) + MappedLength - 1;
132         m_StartUsermodeVa = UsermodeBaseAddress;
133     };
134 
135     VOID
ClearMappedAddressFxRegisterResourceInfo136     ClearMappedAddress(
137         VOID
138         )
139     {
140         m_StartSystemVa = NULL;
141         m_EndSystemVa = NULL;
142         m_StartUsermodeVa = NULL;
143         m_MappedLength = 0;
144     };
145 
146 };
147 
148 struct FxPortResourceInfo : FxStump {
149     //
150     // start physical address
151     //
152     PHYSICAL_ADDRESS m_StartPa;
153 
154     //
155     // end physical address
156     //
157     PHYSICAL_ADDRESS m_EndPa;
158 
159     //
160     // Length of resource
161     //
162     SIZE_T m_Length;
163 
164     static
165     NTSTATUS
_CreateAndInitFxPortResourceInfo166     _CreateAndInit(
167         _In_ PFX_DRIVER_GLOBALS DriverGlobals,
168         _In_ ULONG Count,
169         _Out_ FxPortResourceInfo** PortTable
170         )
171     {
172         NTSTATUS status;
173         FxPortResourceInfo* table;
174 
175         ASSERT(PortTable != NULL);
176         *PortTable = NULL;
177 
178         table = new (DriverGlobals) FxPortResourceInfo[Count];
179         if (table == NULL) {
180             status = STATUS_INSUFFICIENT_RESOURCES;
181             DoTraceLevelMessage(
182                 DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
183                 "Failed to allocate Resource table %!STATUS!", status);
184             return status;
185         }
186 
187         *PortTable = table;
188         status = STATUS_SUCCESS;
189 
190         return status;
191     }
192 
FxPortResourceInfoFxPortResourceInfo193     FxPortResourceInfo(
194         VOID
195         ):
196         m_Length(0)
197     {
198         m_StartPa.QuadPart = 0;
199         m_EndPa.QuadPart = 0;
200     };
201 
~FxPortResourceInfoFxPortResourceInfo202     ~FxPortResourceInfo(){;};
203 
204     VOID
SetPhysicalAddressFxPortResourceInfo205     SetPhysicalAddress(
206         __in PHYSICAL_ADDRESS StartPa,
207         __in SIZE_T Length
208         )
209     {
210         m_StartPa = StartPa;
211         m_EndPa.QuadPart = StartPa.QuadPart + Length - 1;
212         m_Length = Length;
213     }
214 };
215 
216 #endif
217 
218 //
219 // Used in FilterResourceRequirements, and QueryResourceRequirements
220 //
221 
222 class FxResourceIo : public FxObject {
223 public:
224     IO_RESOURCE_DESCRIPTOR m_Descriptor;
225 
226     //
227     // Clone of m_Descriptor which is returned to the driver writer when it
228     // requests a descriptor pointer.  We clone the descriptor so that if the
229     // driver writer attempts to modify the pointer in place, they modify the
230     // clone and not the real descriptor.
231     //
232     IO_RESOURCE_DESCRIPTOR m_DescriptorClone;
233 
234 public:
FxResourceIo(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PIO_RESOURCE_DESCRIPTOR Resource)235     FxResourceIo(
236         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
237         __in PIO_RESOURCE_DESCRIPTOR Resource
238         ) : FxObject(FX_TYPE_RESOURCE_IO, 0, FxDriverGlobals)
239     {
240         RtlCopyMemory(&m_Descriptor, Resource, sizeof(m_Descriptor));
241     }
242 
243     DECLARE_INTERNAL_NEW_OPERATOR();
244 };
245 
246 //
247 // Used in StartDevice
248 //
249 class FxResourceCm : public FxObject {
250 public:
251     CM_PARTIAL_RESOURCE_DESCRIPTOR m_Descriptor;
252 
253     //
254     // Clone of m_Descriptor which is returned to the driver writer when it
255     // requests a descriptor pointer.  We clone the descriptor so that if the
256     // driver writer attempts to modify the pointer in place, they modify the
257     // clone and not the real descriptor.
258     //
259     CM_PARTIAL_RESOURCE_DESCRIPTOR m_DescriptorClone;
260 
261 public:
FxResourceCm(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource)262     FxResourceCm(
263         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
264         __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource
265         ) : FxObject(FX_TYPE_RESOURCE_CM, 0, FxDriverGlobals)
266     {
267         RtlCopyMemory(&m_Descriptor, Resource, sizeof(m_Descriptor));
268     }
269 
270     DECLARE_INTERNAL_NEW_OPERATOR();
271 };
272 
273 enum FxResourceAccessFlags {
274     FxResourceNoAccess      = 0x0000,
275     FxResourceAddAllowed    = 0x0001,
276     FxResourceRemoveAllowed = 0x0002,
277     FxResourceAllAccessAllowed = FxResourceAddAllowed | FxResourceRemoveAllowed,
278 };
279 
280 class FxResourceCollection : public FxCollection {
281 protected:
FxResourceCollection(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in WDFTYPE Type,__in USHORT Size,__in UCHAR AccessFlags=FxResourceNoAccess)282     FxResourceCollection(
283         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
284         __in WDFTYPE Type,
285         __in USHORT Size,
286         __in UCHAR AccessFlags = FxResourceNoAccess
287         ) : FxCollection(FxDriverGlobals, Type, Size),
288             m_AccessFlags(AccessFlags), m_Changed(FALSE)
289     {
290         //
291         // Driver cannot delete this or any of its derivations
292         //
293         MarkNoDeleteDDI();
294     }
295 
296 public:
297 
298     BOOLEAN
299     RemoveAndDelete(
300         __in ULONG Index
301         );
302 
303     _Must_inspect_result_
304     NTSTATUS
305     AddAt(
306         __in ULONG Index,
307         __in FxObject* Object
308         );
309 
310     BOOLEAN
IsRemoveAllowed(VOID)311     IsRemoveAllowed(
312         VOID
313         )
314     {
315         return FLAG_TO_BOOL(m_AccessFlags, FxResourceRemoveAllowed);
316     }
317 
318     BOOLEAN
IsAddAllowed(VOID)319     IsAddAllowed(
320         VOID
321         )
322     {
323         return FLAG_TO_BOOL(m_AccessFlags, FxResourceAddAllowed);
324     }
325 
326     VOID
MarkChanged(VOID)327     MarkChanged(
328         VOID
329         )
330     {
331         m_Changed = TRUE;
332     }
333 
334     BOOLEAN
IsChanged(VOID)335     IsChanged(
336         VOID
337         )
338     {
339         return m_Changed;
340     }
341 
342 public:
343     UCHAR m_AccessFlags;
344 
345     BOOLEAN m_Changed;
346 };
347 
348 class FxCmResList : public FxResourceCollection {
349 
350 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
351 protected:
352     //
353     // Table of mapped register resources
354     //
355     FxRegisterResourceInfo* m_RegisterResourceTable;
356     ULONG m_RegisterResourceTableSizeCe;
357 
358     //
359     // Table of port resources
360     //
361     FxPortResourceInfo* m_PortResourceTable;
362     ULONG m_PortResourceTableSizeCe;
363 
364     //
365     // TRUE if we have at least one CmResourceTypeConnection resource.
366     //
367     BOOLEAN m_HasConnectionResources;
368 
369     //
370     // Lock to serialize access to port/register resource table
371     //
372     MxLock m_ResourceTableLock;
373 
374 #endif // FX_CORE_USER_MODE
375 
376 protected:
FxCmResList(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in UCHAR AccessFlags)377     FxCmResList(
378         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
379         __in UCHAR AccessFlags
380         ) : FxResourceCollection(FxDriverGlobals,
381                                  FX_TYPE_CM_RES_LIST,
382                                  sizeof(FxCmResList),
383                                  AccessFlags)
384     {
385 #if (FX_CORE_MODE==FX_CORE_USER_MODE)
386         m_RegisterResourceTable = NULL;
387         m_PortResourceTable = NULL;
388         m_RegisterResourceTableSizeCe = 0;
389         m_PortResourceTableSizeCe = 0;
390         m_HasConnectionResources = FALSE;
391 #endif // FX_CORE_USER_MODE
392     }
393 
394     ~FxCmResList();
395 
396 public:
397     static
398     _Must_inspect_result_
399     NTSTATUS
_CreateAndInit(__in FxCmResList ** ResourceList,__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in CfxDevice * Device,__in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes,__in UCHAR AccessFlags)400     _CreateAndInit(
401         __in FxCmResList** ResourceList,
402         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
403         __in CfxDevice * Device,
404         __in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes,
405         __in UCHAR AccessFlags
406         )
407     {
408         NTSTATUS ntStatus;
409         FxCmResList *resList = NULL;
410 
411         UNREFERENCED_PARAMETER(Device);
412 
413         //
414         // Initialize
415         //
416         *ResourceList = NULL;
417 
418         //
419         // Allocate a new resource list object
420         //
421         resList = new(FxDriverGlobals, ListAttributes)
422             FxCmResList(FxDriverGlobals, AccessFlags);
423 
424         if (resList == NULL) {
425 
426             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
427 
428             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR,
429                                 TRACINGDEVICE,
430                                 "Failed to allocate FxCmResList, "
431                                 "returning %!STATUS!",
432                                 ntStatus);
433             goto exit;
434         }
435 
436         *ResourceList = resList;
437         ntStatus = STATUS_SUCCESS;
438 
439     exit:
440         if (!NT_SUCCESS(ntStatus)) {
441             if (NULL != resList) {
442                 resList->DeleteFromFailedCreate();
443             }
444         }
445         return ntStatus;
446     }
447 
448     WDFCMRESLIST
GetHandle(VOID)449     GetHandle(
450         VOID
451         )
452     {
453         return (WDFCMRESLIST) GetObjectHandle();
454     }
455 
456     _Must_inspect_result_
457     NTSTATUS
458     BuildFromWdmList(
459         __in PCM_RESOURCE_LIST ResourceList,
460         __in UCHAR AccessFlags
461         );
462 
463     _Must_inspect_result_
464     PCM_RESOURCE_LIST
465     CreateWdmList(
466         __in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType = PagedPool
467         );
468 
469     ULONG
470     GetCount(
471         VOID
472         );
473 
474     PCM_PARTIAL_RESOURCE_DESCRIPTOR
475     GetDescriptor(
476         __in ULONG Index
477         );
478 
479 #if (FX_CORE_MODE == FX_CORE_USER_MODE)
480 
481     //
482     // Lock functions used internally
483     //
484     __inline
485     void
486 #pragma prefast(suppress:__WARNING_UNEXPECTED_IRQL_CHANGE, "UM has no IRQL")
LockResourceTable()487     LockResourceTable(
488         )
489     {
490         KIRQL oldIrql;
491 
492         m_ResourceTableLock.Acquire(&oldIrql);
493 
494         UNREFERENCED_PARAMETER(oldIrql);
495     }
496 
497     __inline
498     void
499 #pragma prefast(suppress:__WARNING_UNEXPECTED_IRQL_CHANGE, "UM has no IRQL")
UnlockResourceTable()500     UnlockResourceTable(
501         )
502     {
503         m_ResourceTableLock.Release(PASSIVE_LEVEL);
504     }
505 
506     NTSTATUS
507     BuildRegisterResourceTable(
508         VOID
509         );
510 
511     NTSTATUS
512     BuildPortResourceTable(
513         VOID
514         );
515 
516     VOID
517     UpdateRegisterResourceEntryLocked(
518         __in FxRegisterResourceInfo* Entry,
519         __in PVOID SystemMappedAddress,
520         __in SIZE_T NumberOfBytes,
521         __in PVOID UsermodeMappedAddress
522         );
523 
524     VOID
525     ClearRegisterResourceEntryLocked(
526         __in FxRegisterResourceInfo* Entry
527         );
528 
529     HRESULT
530     ValidateRegisterPhysicalAddressRange (
531         __in PHYSICAL_ADDRESS PhysicalAddress,
532         __in SIZE_T Size,
533         __out FxRegisterResourceInfo** TableEntry
534         );
535 
536     HRESULT
537     ValidateRegisterSystemBaseAddress (
538         __in PVOID Address,
539         __out PVOID* UsermodeBaseAddress
540         );
541 
542     HRESULT
543     ValidateRegisterSystemAddressRange (
544         __in PVOID SystemAddress,
545         __in SIZE_T Length,
546         __out_opt PVOID* UsermodeAddress
547         );
548 
549     HRESULT
550     ValidateAndClearMapping(
551         __in PVOID Address,
552         __in SIZE_T Length
553         );
554 
555     HRESULT
556     ValidatePortAddressRange(
557         __in PVOID Address,
558         __in SIZE_T Length
559         );
560 
561     SIZE_T
562     GetResourceLength(
563         __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
564         __out_opt PHYSICAL_ADDRESS* Start
565         );
566 
567     HRESULT
568     MapIoSpaceWorker(
569         __in PHYSICAL_ADDRESS PhysicalAddress,
570         __in SIZE_T NumberOfBytes,
571         __in MEMORY_CACHING_TYPE  CacheType,
572         __deref_out VOID** PseudoBaseAddress
573         );
574 
575     VOID
576     ValidateResourceUnmap(
577         VOID
578         );
579 
580     VOID
DeleteRegisterResourceTable(VOID)581     DeleteRegisterResourceTable(
582         VOID
583         )
584     {
585         LockResourceTable();
586         if (m_RegisterResourceTable != NULL) {
587             delete [] m_RegisterResourceTable;
588             m_RegisterResourceTable = NULL;
589             m_RegisterResourceTableSizeCe = 0;
590         }
591         UnlockResourceTable();
592     }
593 
594     VOID
DeletePortResourceTable(VOID)595     DeletePortResourceTable(
596         VOID
597         )
598     {
599         LockResourceTable();
600         if (m_PortResourceTable != NULL) {
601             delete [] m_PortResourceTable;
602             m_PortResourceTable = NULL;
603             m_PortResourceTableSizeCe = 0;
604         }
605         UnlockResourceTable();
606     }
607 
608     _Must_inspect_result_
609     NTSTATUS
610     CheckForConnectionResources(
611         VOID
612         );
613 
614     BOOLEAN
HasConnectionResources(VOID)615     HasConnectionResources(
616         VOID
617         )
618     {
619         return m_HasConnectionResources;
620     }
621 
622 #endif // FX_CORE_USER_MODE
623 
624 };
625 
626 class FxIoResReqList : public FxResourceCollection {
627 protected:
FxIoResReqList(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in UCHAR AccessFlags=FxResourceNoAccess)628     FxIoResReqList(
629         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
630         __in UCHAR AccessFlags = FxResourceNoAccess
631         ) :
632         FxResourceCollection(FxDriverGlobals,
633                              FX_TYPE_IO_RES_REQ_LIST,
634                              sizeof(FxIoResReqList),
635                              AccessFlags),
636         m_SlotNumber(0), m_InterfaceType(Internal)
637     {
638         m_AccessFlags = AccessFlags;
639     }
640 
641 public:
642 
643     static
644     _Must_inspect_result_
645     NTSTATUS
_CreateAndInit(__in FxIoResReqList ** ResourceReqList,__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes,__in UCHAR AccessFlags)646     _CreateAndInit(
647         __in FxIoResReqList** ResourceReqList,
648         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
649         __in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes,
650         __in UCHAR AccessFlags
651         )
652     {
653         NTSTATUS ntStatus;
654         FxIoResReqList *resReqList = NULL;
655 
656         //
657         // Initialize
658         //
659         *ResourceReqList = NULL;
660 
661         //
662         // Allocate a new resource list object
663         //
664         resReqList = new(FxDriverGlobals, ListAttributes)
665             FxIoResReqList(FxDriverGlobals, AccessFlags);
666         if (resReqList == NULL) {
667             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
668 
669             DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR,
670                                 TRACINGDEVICE,
671                                 "Failed to allocate FxIoResReqList, "
672                                 "returning %!STATUS!",
673                                 ntStatus);
674 
675             goto exit;
676         }
677 
678         *ResourceReqList = resReqList;
679         ntStatus = STATUS_SUCCESS;
680 
681         exit:
682             if (!NT_SUCCESS(ntStatus)) {
683                 if (NULL != resReqList) {
684                     resReqList->DeleteFromFailedCreate();
685                 }
686             }
687             return ntStatus;
688     }
689 
690     WDFIORESREQLIST
GetHandle(VOID)691     GetHandle(
692         VOID
693         )
694     {
695         return (WDFIORESREQLIST) GetObjectHandle();
696     }
697 
698     static
699     _Must_inspect_result_
700     FxIoResReqList*
701     _CreateFromWdmList(
702         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
703         __in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList,
704         __in UCHAR AccessFlags
705         );
706 
707     _Must_inspect_result_
708     PIO_RESOURCE_REQUIREMENTS_LIST
709     CreateWdmList(
710         VOID
711         );
712 
713 public:
714     ULONG m_SlotNumber;
715 
716     INTERFACE_TYPE m_InterfaceType;
717 };
718 
719 class FxIoResList : public FxResourceCollection {
720 public:
FxIoResList(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in FxIoResReqList * RequirementsList)721     FxIoResList(
722         __in PFX_DRIVER_GLOBALS FxDriverGlobals,
723         __in FxIoResReqList* RequirementsList
724         ) :
725         FxResourceCollection(FxDriverGlobals, FX_TYPE_IO_RES_LIST, sizeof(FxIoResList)),
726         m_OwningList(RequirementsList)
727     {
728         m_AccessFlags = RequirementsList->m_AccessFlags;
729     }
730 
731     WDFIORESLIST
GetHandle(VOID)732     GetHandle(
733         VOID
734         )
735     {
736         return (WDFIORESLIST) GetObjectHandle();
737     }
738 
739     _Must_inspect_result_
740     NTSTATUS
741     BuildFromWdmList(
742         __deref_in PIO_RESOURCE_LIST* WdmResourceList
743         );
744 
745 public:
746     FxIoResReqList* m_OwningList;
747 };
748 
749 #endif // _FXRESOURCE_H_
750