1 /*++
2
3 Copyright (c) Microsoft Corporation
4
5 Module Name:
6
7 FxResourceCollection.cpp
8
9 Abstract:
10
11 This module implements a base object for derived collection classes and
12 the derived collection classes.
13
14 Author:
15
16
17
18 Environment:
19
20 Both kernel and user mode
21
22 Revision History:
23
24 --*/
25
26 #include "fxsupportpch.hpp"
27
28 extern "C" {
29 #if defined(EVENT_TRACING)
30 #include "FxResourceCollection.tmh"
31 #endif
32 }
33
34 BOOLEAN
RemoveAndDelete(__in ULONG Index)35 FxResourceCollection::RemoveAndDelete(
36 __in ULONG Index
37 )
38 /*++
39
40 Routine Description:
41 Removes an entry from the collection and then deletes it if found. The
42 caller must have removal permissions to perform this action.
43
44 Arguments:
45 Index - zero based index into the collection at which to perform the removal
46
47 Return Value:
48 TRUE if the item was found and deleted, FALSE otherwise
49
50 --*/
51 {
52 FxObject* pObject;
53 FxCollectionEntry* pEntry;
54 KIRQL irql;
55
56 if (IsRemoveAllowed() == FALSE) {
57 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
58 "Removes not allowed on handle %p, remove at index %d"
59 "failed", GetObjectHandle(), Index);
60
61 FxVerifierDbgBreakPoint(GetDriverGlobals());
62 return FALSE;
63 }
64
65 pObject = NULL;
66
67 Lock(&irql);
68
69 pEntry = FindEntry(Index);
70 if (pEntry != NULL) {
71
72 //
73 // Mark the list as changed so when we go to create a WDM resource list we
74 // know if a new list is needed.
75 //
76 MarkChanged();
77
78 pObject = pEntry->m_Object;
79
80 //
81 // Remove the entry
82 //
83 RemoveEntry(pEntry);
84 }
85 Unlock(irql);
86
87 if (pObject != NULL) {
88 //
89 // Delete the object since we created it
90 //
91 pObject->DeleteObject();
92 pObject = NULL;
93
94 return TRUE;
95 }
96 else {
97 return FALSE;
98 }
99 }
100
101 _Must_inspect_result_
102 NTSTATUS
AddAt(__in ULONG Index,__in FxObject * Object)103 FxResourceCollection::AddAt(
104 __in ULONG Index,
105 __in FxObject* Object
106 )
107 /*++
108
109 Routine Description:
110 Adds an object into the collection at the specified index.
111
112 Arguments:
113 Index - zero baesd index in which to insert into the list. WDF_INSERT_AT_END
114 is a special value which indicates that the insertion is an append.
115
116 Object - object to add
117
118 Return Value:
119 NTSTATUS
120
121 --*/
122 {
123 FxCollectionEntry *pNew;
124 PLIST_ENTRY ple;
125 NTSTATUS status;
126 KIRQL irql;
127
128 if (IsAddAllowed() == FALSE) {
129 DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
130 "Adds not allowed on handle %p, add at index %d"
131 "failed", GetObjectHandle(), Index);
132
133 FxVerifierDbgBreakPoint(GetDriverGlobals());
134
135 return STATUS_ACCESS_DENIED;
136 }
137
138 Lock(&irql);
139
140 ple = NULL;
141 status = STATUS_SUCCESS;
142
143 pNew = AllocateEntry(GetDriverGlobals());
144
145 if (pNew != NULL) {
146 //
147 // Inserting at the current count (i.e. one past the end) is the same
148 // as append.
149 //
150 if (Index == WDF_INSERT_AT_END || Index == Count()) {
151 ple = &m_ListHead;
152 }
153 else {
154 FxCollectionEntry* cur, *end;
155 ULONG i;
156
157 for (cur = Start(), end = End(), i = 0;
158 cur != end;
159 cur = cur->Next(), i++) {
160 if (i == Index) {
161 ple = &cur->m_ListEntry;
162 break;
163 }
164 }
165
166 if (ple == NULL) {
167 delete pNew;
168 status = STATUS_ARRAY_BOUNDS_EXCEEDED;
169 }
170 }
171 }
172 else {
173 status = STATUS_INSUFFICIENT_RESOURCES;
174 }
175
176 if (NT_SUCCESS(status)) {
177 PLIST_ENTRY blink;
178
179 // ple now points to the list entry which we will insert our node
180 // *before*
181
182 blink = ple->Blink;
183
184 // Link the previous with the new entry
185 blink->Flink = &pNew->m_ListEntry;
186 pNew->m_ListEntry.Blink = blink;
187
188 // Link the current with the new entry
189 pNew->m_ListEntry.Flink = ple;
190 ple->Blink = &pNew->m_ListEntry;
191
192 AddEntry(pNew, Object);
193
194 //
195 // Mark the list as changed so when we go to create a WDM resource list
196 // we know if a new list is needed.
197 //
198 MarkChanged();
199 }
200
201 Unlock(irql);
202
203 if (!NT_SUCCESS(status)) {
204 Object->DeleteFromFailedCreate();
205 }
206
207 return status;
208 }
209
210 _Must_inspect_result_
211 NTSTATUS
BuildFromWdmList(__deref_in PIO_RESOURCE_LIST * WdmResourceList)212 FxIoResList::BuildFromWdmList(
213 __deref_in PIO_RESOURCE_LIST* WdmResourceList
214 )
215 /*++
216
217 Routine Description:
218 Builds up the collection with FxResourceIo objects based on the passed in
219 WDM io resource list
220
221 Arguments:
222 WdmResourceList - list which specifies the io resource objects to create
223
224 Return Value:
225 NTSTATUS
226
227 --*/
228 {
229 PIO_RESOURCE_DESCRIPTOR pWdmDescriptor;
230 ULONG i, count;
231 NTSTATUS status;
232
233 pWdmDescriptor = &(*WdmResourceList)->Descriptors[0];
234 count = (*WdmResourceList)->Count;
235 status = STATUS_SUCCESS;
236
237 for (i = 0; i < count; i++) {
238 //
239 // Now create a new resource object for each resource
240 // in our list.
241 //
242 FxResourceIo *pResource;
243
244 pResource = new(GetDriverGlobals())
245 FxResourceIo(GetDriverGlobals(), pWdmDescriptor);
246
247 if (pResource == NULL) {
248 //
249 // We failed, clean up, and exit. Since we are only
250 // keeping references on the master collection, if
251 // we free this, everything else will go away too.
252 //
253 status = STATUS_INSUFFICIENT_RESOURCES;
254 }
255
256 if (NT_SUCCESS(status)) {
257 status = pResource->AssignParentObject(this);
258
259 //
260 // See notes in previous AssignParentObject as to why
261 // we are asserting.
262 //
263 ASSERT(NT_SUCCESS(status));
264 UNREFERENCED_PARAMETER(status);
265
266 status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
267 }
268
269 if (!NT_SUCCESS(status)) {
270 break;
271 }
272
273 pWdmDescriptor++;
274 }
275
276 if (NT_SUCCESS(status)) {
277 status = m_OwningList->Add(this) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
278 }
279
280 if (NT_SUCCESS(status)) {
281 *WdmResourceList = (PIO_RESOURCE_LIST) pWdmDescriptor;
282 }
283
284 return status;
285 }
286
287 _Must_inspect_result_
288 NTSTATUS
BuildFromWdmList(__in PCM_RESOURCE_LIST WdmResourceList,__in UCHAR AccessFlags)289 FxCmResList::BuildFromWdmList(
290 __in PCM_RESOURCE_LIST WdmResourceList,
291 __in UCHAR AccessFlags
292 )
293 /*++
294
295 Routine Description:
296 Builds up the collection with FxResourceCm objects based on the passed in
297 WDM io resource list.
298
299 Arguments:
300 WdmResourceList - list which specifies the io resource objects to create
301
302 AccessFlags - permissions to be associated with the list
303
304 Return Value:
305 NTSTATUS
306
307 --*/
308 {
309 NTSTATUS status;
310
311 //
312 // Predispose to success
313 //
314 status = STATUS_SUCCESS;
315
316 Clear();
317
318 m_AccessFlags = AccessFlags;
319
320 if (WdmResourceList != NULL) {
321 PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
322 ULONG count, i;
323
324 //
325 // We only expect to see one full resource descriptor.
326 //
327 ASSERT(WdmResourceList->Count == 1);
328
329 count = WdmResourceList->List[0].PartialResourceList.Count;
330 pDescriptor = WdmResourceList->List[0].PartialResourceList.PartialDescriptors;
331
332 for(i = 0; i < count; i++, pDescriptor++) {
333 FxResourceCm *pResource;
334
335 pResource = new(GetDriverGlobals())
336 FxResourceCm(GetDriverGlobals(), pDescriptor);
337
338 if (pResource == NULL) {
339 status = STATUS_INSUFFICIENT_RESOURCES;
340 }
341
342 if (NT_SUCCESS(status)) {
343 status = pResource->AssignParentObject(this);
344
345 //
346 // Since we control our own lifetime here, the assign should
347 // always work.
348 //
349 ASSERT(NT_SUCCESS(status));
350
351 status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES;
352 }
353
354 if (!NT_SUCCESS(status)) {
355 Clear();
356 break;
357 }
358 }
359 }
360
361 return status;
362 }
363
364 _Must_inspect_result_
365 PCM_RESOURCE_LIST
CreateWdmList(__in __drv_strictTypeMatch (__drv_typeExpr)POOL_TYPE PoolType)366 FxCmResList::CreateWdmList(
367 __in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType
368 )
369 /*++
370
371 Routine Description:
372 Allocates and initializes a WDM CM resource list based off of the current
373 contents of this collection.
374
375 Arguments:
376 PoolType - the pool type from which to allocate the resource list
377
378 Return Value:
379 a new resource list upon success, NULL upon failure
380
381 --*/
382 {
383 PCM_RESOURCE_LIST pWdmResourceList;
384 ULONG size;
385 PFX_DRIVER_GLOBALS pFxDriverGlobals;
386
387 pWdmResourceList = NULL;
388 pFxDriverGlobals = GetDriverGlobals();
389
390 if (Count()) {
391 //
392 // NOTE: This function assumes all resources are on the same bus
393 // and therefore there is only one FULL_RESOURCE_DESCRIPTOR.
394 //
395 size = sizeof(CM_RESOURCE_LIST) +
396 (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count() - 1));
397
398 pWdmResourceList = (PCM_RESOURCE_LIST)
399 MxMemory::MxAllocatePoolWithTag(PoolType, size, pFxDriverGlobals->Tag);
400
401 if (pWdmResourceList != NULL) {
402 PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;
403 FxCollectionEntry *cur, *end;
404
405 RtlZeroMemory(pWdmResourceList, size);
406
407 pWdmResourceList->Count = 1; // We only return one full descriptor
408
409 pWdmResourceList->List[0].PartialResourceList.Version = 1;
410 pWdmResourceList->List[0].PartialResourceList.Revision = 1;
411 pWdmResourceList->List[0].PartialResourceList.Count = Count();
412
413 pDescriptor =
414 pWdmResourceList->List[0].PartialResourceList.PartialDescriptors;
415
416 end = End();
417 for (cur = Start(); cur != end; cur = cur->Next()) {
418 FxResourceCm *pResource;
419
420 pResource = (FxResourceCm*) cur->m_Object;
421
422 RtlCopyMemory(pDescriptor,
423 &pResource->m_Descriptor,
424 sizeof(pResource->m_Descriptor));
425 pDescriptor++;
426 }
427 }
428 }
429
430 return pWdmResourceList;
431 }
432
433 ULONG
GetCount(VOID)434 FxCmResList::GetCount(
435 VOID
436 )
437 {
438 ULONG count;
439 KIRQL irql;
440
441 Lock(&irql);
442 count = Count();
443 Unlock(irql);
444
445 return count;
446 }
447
448 PCM_PARTIAL_RESOURCE_DESCRIPTOR
GetDescriptor(__in ULONG Index)449 FxCmResList::GetDescriptor(
450 __in ULONG Index
451 )
452 {
453 FxResourceCm* pObject;
454 KIRQL irql;
455
456 Lock(&irql);
457 pObject = (FxResourceCm*) GetItem(Index);
458 Unlock(irql);
459
460 if (pObject == NULL) {
461 return NULL;
462 }
463 else {
464 //
465 // Copy the current descriptor to the clone and return it
466 //
467 RtlCopyMemory(&pObject->m_DescriptorClone,
468 &pObject->m_Descriptor,
469 sizeof(pObject->m_Descriptor));
470
471 return &pObject->m_DescriptorClone;
472 }
473 }
474
475 _Must_inspect_result_
476 FxIoResReqList*
_CreateFromWdmList(__in PFX_DRIVER_GLOBALS FxDriverGlobals,__in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList,__in UCHAR AccessFlags)477 FxIoResReqList::_CreateFromWdmList(
478 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
479 __in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList,
480 __in UCHAR AccessFlags
481 )
482 /*++
483
484 Routine Description:
485 Allocates and populates an FxIoResReqList based on the WDM resource
486 requirements list.
487
488 Arguments:
489 WdmRequirementsList - a list of IO_RESOURCE_LISTs which will indicate how
490 to fill in the returned collection object
491
492 AccessFlags - permissions to associate with the newly created object
493
494 Return Value:
495 a new object upon success, NULL upon failure
496
497 --*/
498
499 {
500 FxIoResReqList* pIoResReqList;
501 ULONG i;
502
503 pIoResReqList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
504 FxIoResReqList(FxDriverGlobals, AccessFlags);
505
506 if (pIoResReqList != NULL) {
507 PIO_RESOURCE_LIST pWdmResourceList;
508 NTSTATUS status;
509
510 if (WdmRequirementsList == NULL) {
511 return pIoResReqList;
512 }
513
514 status = STATUS_SUCCESS;
515 pWdmResourceList = &WdmRequirementsList->List[0];
516
517 pIoResReqList->m_InterfaceType = WdmRequirementsList->InterfaceType;
518 pIoResReqList->m_SlotNumber = WdmRequirementsList->SlotNumber;
519
520 for (i = 0; i < WdmRequirementsList->AlternativeLists; i++) {
521 FxIoResList *pResList;
522
523 pResList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES)
524 FxIoResList(FxDriverGlobals, pIoResReqList);
525
526 if (pResList != NULL) {
527 status = pResList->AssignParentObject(pIoResReqList);
528
529 //
530 // Since we control our own lifetime, assigning the parent should
531 // never fail.
532 //
533 ASSERT(NT_SUCCESS(status));
534
535 status = pResList->BuildFromWdmList(&pWdmResourceList);
536 }
537 else {
538 //
539 // We failed to allocate a child collection. Clean up
540 // and break out of the loop.
541 //
542 status = STATUS_INSUFFICIENT_RESOURCES;
543 }
544
545 if (!NT_SUCCESS(status)) {
546 break;
547 }
548 }
549
550 if (!NT_SUCCESS(status)) {
551 //
552 // Cleanup and return a NULL object
553 //
554 pIoResReqList->DeleteObject();
555 pIoResReqList = NULL;
556 }
557 }
558
559 return pIoResReqList;
560 }
561
562 _Must_inspect_result_
563 PIO_RESOURCE_REQUIREMENTS_LIST
CreateWdmList(VOID)564 FxIoResReqList::CreateWdmList(
565 VOID
566 )
567 /*++
568
569 Routine Description:
570 Creates a WDM io resource requirements list based off of the current
571 contents of the collection
572
573 Arguments:
574 None
575
576 Return Value:
577 new WDM io resource requirements list allocated out of paged pool upon success,
578 NULL upon failure or an empty list
579
580 --*/
581 {
582 PIO_RESOURCE_REQUIREMENTS_LIST pRequirementsList;
583 FxCollectionEntry *cur, *end;
584 NTSTATUS status;
585 ULONG totalDescriptors;
586 ULONG size;
587 ULONG count;
588 ULONG tmp;
589 PFX_DRIVER_GLOBALS pFxDriverGlobals;
590
591 totalDescriptors = 0;
592 pRequirementsList = NULL;
593
594 count = Count();
595 pFxDriverGlobals = GetDriverGlobals();
596
597 if (count > 0) {
598 //
599 // The collection object should contain a set of child collections
600 // with each of the various requirement lists. Use the number of
601 // these collections to determine the size of our requirements
602 // list.
603 //
604 end = End();
605 for (cur = Start(); cur != end; cur = cur->Next()) {
606 status = RtlULongAdd(totalDescriptors,
607 ((FxIoResList *) cur->m_Object)->Count(),
608 &totalDescriptors);
609
610 if (!NT_SUCCESS(status)) {
611 goto Overflow;
612 }
613 }
614
615 //
616 // We now have enough information to determine how much memory we
617 // need to allocate for our requirements list.
618 //
619 // size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) +
620 // (sizeof(IO_RESOURCE_LIST) * (count - 1)) +
621 // (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors) -
622 // (sizeof(IO_RESOURCE_DESCRIPTOR) * count);
623 //
624 // sizeof(IO_RESOURCE_DESCRIPTOR) * count is subtracted off because
625 // each IO_RESOURCE_LIST has an embedded IO_RESOURCE_DESCRIPTOR in it
626 // and we don't want to overallocated.
627 //
628
629 //
630 // To handle overflow each mathematical operation is split out into an
631 // overflow safe call.
632 //
633 size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST);
634
635 // sizeof(IO_RESOURCE_LIST) * (count - 1)
636 status = RtlULongMult(sizeof(IO_RESOURCE_LIST), count - 1, &tmp);
637 if (!NT_SUCCESS(status)) {
638 goto Overflow;
639 }
640
641 status = RtlULongAdd(size, tmp, &size);
642 if (!NT_SUCCESS(status)) {
643 goto Overflow;
644 }
645
646 // (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors)
647 status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR),
648 totalDescriptors,
649 &tmp);
650 if (!NT_SUCCESS(status)) {
651 goto Overflow;
652 }
653
654 status = RtlULongAdd(size, tmp, &size);
655 if (!NT_SUCCESS(status)) {
656 goto Overflow;
657 }
658
659 // - sizeof(IO_RESOURCE_DESCRIPTOR) * Count() (note the subtraction!)
660 status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR), count, &tmp);
661 if (!NT_SUCCESS(status)) {
662 goto Overflow;
663 }
664
665 // Sub, not Add!
666 status = RtlULongSub(size, tmp, &size);
667 if (!NT_SUCCESS(status)) {
668 goto Overflow;
669 }
670
671 pRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST)
672 MxMemory::MxAllocatePoolWithTag(PagedPool, size, pFxDriverGlobals->Tag);
673
674 if (pRequirementsList != NULL) {
675 PIO_RESOURCE_LIST pList;
676 FxResourceIo *pResource;
677
678 pList = pRequirementsList->List;
679
680 //
681 // Start by zero initializing our structure
682 //
683 RtlZeroMemory(pRequirementsList, size);
684
685 //
686 // InterfaceType and BusNumber are unused for WDM, but InterfaceType
687 // is used by the arbiters.
688 //
689 pRequirementsList->InterfaceType = m_InterfaceType;
690
691 pRequirementsList->SlotNumber = m_SlotNumber;
692
693 //
694 // Now populate the requirements list with the resources from
695 // our collections.
696 //
697 pRequirementsList->ListSize = size;
698 pRequirementsList->AlternativeLists = Count();
699
700 end = End();
701 for (cur = Start(); cur != end; cur = cur->Next()) {
702 FxIoResList* pIoResList;
703 PIO_RESOURCE_DESCRIPTOR pDescriptor;
704 FxCollectionEntry *pIoResCur, *pIoResEnd;
705
706 pIoResList = (FxIoResList*) cur->m_Object;
707
708 pList->Version = 1;
709 pList->Revision = 1;
710 pList->Count = pIoResList->Count();
711
712 pDescriptor = pList->Descriptors;
713
714 pIoResEnd = pIoResList->End();
715 for (pIoResCur = pIoResList->Start();
716 pIoResCur != pIoResEnd;
717 pIoResCur = pIoResCur->Next()) {
718
719 pResource = (FxResourceIo *) pIoResCur->m_Object;
720 RtlCopyMemory(pDescriptor,
721 &pResource->m_Descriptor,
722 sizeof(pResource->m_Descriptor));
723 pDescriptor++;
724 }
725
726 pList = (PIO_RESOURCE_LIST) pDescriptor;
727 }
728 }
729 }
730
731 return pRequirementsList;
732
733 Overflow:
734 DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP,
735 "Integer overflow occured when computing size of "
736 "IO_RESOURCE_REQUIREMENTS_LIST");
737
738 return NULL;
739 }
740