xref: /reactos/ntoskrnl/io/pnpmgr/pnpres.c (revision 49358f34)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * COPYRIGHT:       GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/io/pnpmgr/pnpres.c
5  * PURPOSE:         Resource handling code
6  * PROGRAMMERS:     Cameron Gutman (cameron.gutman@reactos.org)
7  *                  ReactOS Portable Systems Group
8  */
9 
10 #include <ntoskrnl.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 FORCEINLINE
16 PIO_RESOURCE_LIST
IopGetNextResourceList(_In_ const IO_RESOURCE_LIST * ResourceList)17 IopGetNextResourceList(
18     _In_ const IO_RESOURCE_LIST *ResourceList)
19 {
20     ASSERT((ResourceList->Count > 0) && (ResourceList->Count < 1000));
21     return (PIO_RESOURCE_LIST)(
22         &ResourceList->Descriptors[ResourceList->Count]);
23 }
24 
25 static
26 BOOLEAN
IopCheckDescriptorForConflict(PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc,OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)27 IopCheckDescriptorForConflict(
28     PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc,
29     OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
30 {
31     CM_RESOURCE_LIST CmList;
32     NTSTATUS Status;
33 
34     CmList.Count = 1;
35     CmList.List[0].InterfaceType = InterfaceTypeUndefined;
36     CmList.List[0].BusNumber = 0;
37     CmList.List[0].PartialResourceList.Version = 1;
38     CmList.List[0].PartialResourceList.Revision = 1;
39     CmList.List[0].PartialResourceList.Count = 1;
40     CmList.List[0].PartialResourceList.PartialDescriptors[0] = *CmDesc;
41 
42     Status = IopDetectResourceConflict(&CmList, TRUE, ConflictingDescriptor);
43     if (Status == STATUS_CONFLICTING_ADDRESSES)
44         return TRUE;
45 
46     return FALSE;
47 }
48 
49 static
50 BOOLEAN
IopFindBusNumberResource(IN PIO_RESOURCE_DESCRIPTOR IoDesc,OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)51 IopFindBusNumberResource(
52     IN PIO_RESOURCE_DESCRIPTOR IoDesc,
53     OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
54 {
55     ULONG Start;
56     CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
57 
58     ASSERT(IoDesc->Type == CmDesc->Type);
59     ASSERT(IoDesc->Type == CmResourceTypeBusNumber);
60 
61     for (Start = IoDesc->u.BusNumber.MinBusNumber;
62          Start <= IoDesc->u.BusNumber.MaxBusNumber - IoDesc->u.BusNumber.Length + 1;
63          Start++)
64     {
65         CmDesc->u.BusNumber.Length = IoDesc->u.BusNumber.Length;
66         CmDesc->u.BusNumber.Start = Start;
67 
68         if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
69         {
70             Start += ConflictingDesc.u.BusNumber.Start + ConflictingDesc.u.BusNumber.Length;
71         }
72         else
73         {
74             DPRINT1("Satisfying bus number requirement with 0x%x (length: 0x%x)\n", Start, CmDesc->u.BusNumber.Length);
75             return TRUE;
76         }
77     }
78 
79     return FALSE;
80 }
81 
82 static
83 BOOLEAN
IopFindMemoryResource(IN PIO_RESOURCE_DESCRIPTOR IoDesc,OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)84 IopFindMemoryResource(
85     IN PIO_RESOURCE_DESCRIPTOR IoDesc,
86     OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
87 {
88     ULONGLONG Start;
89     CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
90 
91     ASSERT(IoDesc->Type == CmDesc->Type);
92     ASSERT(IoDesc->Type == CmResourceTypeMemory);
93 
94     /* HACK */
95     if (IoDesc->u.Memory.Alignment == 0)
96         IoDesc->u.Memory.Alignment = 1;
97 
98     for (Start = (ULONGLONG)IoDesc->u.Memory.MinimumAddress.QuadPart;
99          Start <= (ULONGLONG)IoDesc->u.Memory.MaximumAddress.QuadPart - IoDesc->u.Memory.Length + 1;
100          Start += IoDesc->u.Memory.Alignment)
101     {
102         CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
103         CmDesc->u.Memory.Start.QuadPart = (LONGLONG)Start;
104 
105         if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
106         {
107             Start += (ULONGLONG)ConflictingDesc.u.Memory.Start.QuadPart +
108                      ConflictingDesc.u.Memory.Length;
109         }
110         else
111         {
112             DPRINT1("Satisfying memory requirement with 0x%I64x (length: 0x%x)\n", Start, CmDesc->u.Memory.Length);
113             return TRUE;
114         }
115     }
116 
117     return FALSE;
118 }
119 
120 static
121 BOOLEAN
IopFindPortResource(IN PIO_RESOURCE_DESCRIPTOR IoDesc,OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)122 IopFindPortResource(
123     IN PIO_RESOURCE_DESCRIPTOR IoDesc,
124     OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
125 {
126     ULONGLONG Start;
127     CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
128 
129     ASSERT(IoDesc->Type == CmDesc->Type);
130     ASSERT(IoDesc->Type == CmResourceTypePort);
131 
132     /* HACK */
133     if (IoDesc->u.Port.Alignment == 0)
134         IoDesc->u.Port.Alignment = 1;
135 
136     for (Start = (ULONGLONG)IoDesc->u.Port.MinimumAddress.QuadPart;
137          Start <= (ULONGLONG)IoDesc->u.Port.MaximumAddress.QuadPart - IoDesc->u.Port.Length + 1;
138          Start += IoDesc->u.Port.Alignment)
139     {
140         CmDesc->u.Port.Length = IoDesc->u.Port.Length;
141         CmDesc->u.Port.Start.QuadPart = (LONGLONG)Start;
142 
143         if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
144         {
145             Start += (ULONGLONG)ConflictingDesc.u.Port.Start.QuadPart + ConflictingDesc.u.Port.Length;
146         }
147         else
148         {
149             DPRINT("Satisfying port requirement with 0x%I64x (length: 0x%x)\n", Start, CmDesc->u.Port.Length);
150             return TRUE;
151         }
152     }
153 
154     DPRINT1("IopFindPortResource failed!\n");
155     return FALSE;
156 }
157 
158 static
159 BOOLEAN
IopFindDmaResource(IN PIO_RESOURCE_DESCRIPTOR IoDesc,OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)160 IopFindDmaResource(
161     IN PIO_RESOURCE_DESCRIPTOR IoDesc,
162     OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
163 {
164     ULONG Channel;
165 
166     ASSERT(IoDesc->Type == CmDesc->Type);
167     ASSERT(IoDesc->Type == CmResourceTypeDma);
168 
169     for (Channel = IoDesc->u.Dma.MinimumChannel;
170          Channel <= IoDesc->u.Dma.MaximumChannel;
171          Channel++)
172     {
173         CmDesc->u.Dma.Channel = Channel;
174         CmDesc->u.Dma.Port = 0;
175 
176         if (!IopCheckDescriptorForConflict(CmDesc, NULL))
177         {
178             DPRINT1("Satisfying DMA requirement with channel 0x%x\n", Channel);
179             return TRUE;
180         }
181     }
182 
183     return FALSE;
184 }
185 
186 static
187 BOOLEAN
IopFindInterruptResource(IN PIO_RESOURCE_DESCRIPTOR IoDesc,OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)188 IopFindInterruptResource(
189     IN PIO_RESOURCE_DESCRIPTOR IoDesc,
190     OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
191 {
192     ULONG Vector;
193 
194     ASSERT(IoDesc->Type == CmDesc->Type);
195     ASSERT(IoDesc->Type == CmResourceTypeInterrupt);
196 
197     for (Vector = IoDesc->u.Interrupt.MinimumVector;
198          Vector <= IoDesc->u.Interrupt.MaximumVector;
199          Vector++)
200     {
201         CmDesc->u.Interrupt.Vector = Vector;
202         CmDesc->u.Interrupt.Level = Vector;
203         CmDesc->u.Interrupt.Affinity = (KAFFINITY)-1;
204 
205         if (!IopCheckDescriptorForConflict(CmDesc, NULL))
206         {
207             DPRINT1("Satisfying interrupt requirement with IRQ 0x%x\n", Vector);
208             return TRUE;
209         }
210     }
211 
212     DPRINT1("Failed to satisfy interrupt requirement with IRQ 0x%x-0x%x\n",
213             IoDesc->u.Interrupt.MinimumVector,
214             IoDesc->u.Interrupt.MaximumVector);
215     return FALSE;
216 }
217 
218 NTSTATUS NTAPI
IopFixupResourceListWithRequirements(IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList,OUT PCM_RESOURCE_LIST * ResourceList)219 IopFixupResourceListWithRequirements(
220     IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList,
221     OUT PCM_RESOURCE_LIST *ResourceList)
222 {
223     ULONG i, OldCount;
224     BOOLEAN AlternateRequired = FALSE;
225     PIO_RESOURCE_LIST ResList;
226 
227     /* Save the initial resource count when we got here so we can restore if an alternate fails */
228     if (*ResourceList != NULL)
229         OldCount = (*ResourceList)->List[0].PartialResourceList.Count;
230     else
231         OldCount = 0;
232 
233     ResList = &RequirementsList->List[0];
234     for (i = 0; i < RequirementsList->AlternativeLists; i++, ResList = IopGetNextResourceList(ResList))
235     {
236         ULONG ii;
237 
238         /* We need to get back to where we were before processing the last alternative list */
239         if (OldCount == 0 && *ResourceList != NULL)
240         {
241             /* Just free it and kill the pointer */
242             ExFreePool(*ResourceList);
243             *ResourceList = NULL;
244         }
245         else if (OldCount != 0)
246         {
247             PCM_RESOURCE_LIST NewList;
248 
249             /* Let's resize it */
250             (*ResourceList)->List[0].PartialResourceList.Count = OldCount;
251 
252             /* Allocate the new smaller list */
253             NewList = ExAllocatePool(PagedPool, PnpDetermineResourceListSize(*ResourceList));
254             if (!NewList)
255                 return STATUS_NO_MEMORY;
256 
257             /* Copy the old stuff back */
258             RtlCopyMemory(NewList, *ResourceList, PnpDetermineResourceListSize(*ResourceList));
259 
260             /* Free the old one */
261             ExFreePool(*ResourceList);
262 
263             /* Store the pointer to the new one */
264             *ResourceList = NewList;
265         }
266 
267         for (ii = 0; ii < ResList->Count; ii++)
268         {
269             ULONG iii;
270             PCM_PARTIAL_RESOURCE_LIST PartialList = (*ResourceList) ? &(*ResourceList)->List[0].PartialResourceList : NULL;
271             PIO_RESOURCE_DESCRIPTOR IoDesc = &ResList->Descriptors[ii];
272             BOOLEAN Matched = FALSE;
273 
274             /* Skip alternates if we don't need one */
275             if (!AlternateRequired && (IoDesc->Option & IO_RESOURCE_ALTERNATIVE))
276             {
277                 DPRINT("Skipping unneeded alternate\n");
278                 continue;
279             }
280 
281             /* Check if we couldn't satsify a requirement or its alternates */
282             if (AlternateRequired && !(IoDesc->Option & IO_RESOURCE_ALTERNATIVE))
283             {
284                 DPRINT1("Unable to satisfy preferred resource or alternates in list %lu\n", i);
285 
286                 /* Break out of this loop and try the next list */
287                 break;
288             }
289 
290             for (iii = 0; PartialList && iii < PartialList->Count && !Matched; iii++)
291             {
292                 /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific),
293                    but only one is allowed and it must be the last one in the list! */
294                 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc = &PartialList->PartialDescriptors[iii];
295 
296                 /* First check types */
297                 if (IoDesc->Type != CmDesc->Type)
298                     continue;
299 
300                 switch (IoDesc->Type)
301                 {
302                     case CmResourceTypeInterrupt:
303                         /* Make sure it satisfies our vector range */
304                         if (CmDesc->u.Interrupt.Vector >= IoDesc->u.Interrupt.MinimumVector &&
305                             CmDesc->u.Interrupt.Vector <= IoDesc->u.Interrupt.MaximumVector)
306                         {
307                             /* Found it */
308                             Matched = TRUE;
309                         }
310                         else
311                         {
312                             DPRINT("Interrupt - Not a match! 0x%x not inside 0x%x to 0x%x\n",
313                                    CmDesc->u.Interrupt.Vector,
314                                    IoDesc->u.Interrupt.MinimumVector,
315                                    IoDesc->u.Interrupt.MaximumVector);
316                         }
317                         break;
318 
319                     case CmResourceTypeMemory:
320                     case CmResourceTypePort:
321                         /* Make sure the length matches and it satisfies our address range */
322                         if (CmDesc->u.Memory.Length == IoDesc->u.Memory.Length &&
323                             (ULONGLONG)CmDesc->u.Memory.Start.QuadPart >= (ULONGLONG)IoDesc->u.Memory.MinimumAddress.QuadPart &&
324                             (ULONGLONG)CmDesc->u.Memory.Start.QuadPart + CmDesc->u.Memory.Length - 1 <= (ULONGLONG)IoDesc->u.Memory.MaximumAddress.QuadPart)
325                         {
326                             /* Found it */
327                             Matched = TRUE;
328                         }
329                         else
330                         {
331                             DPRINT("Memory/Port - Not a match! 0x%I64x with length 0x%x not inside 0x%I64x to 0x%I64x with length 0x%x\n",
332                                    CmDesc->u.Memory.Start.QuadPart,
333                                    CmDesc->u.Memory.Length,
334                                    IoDesc->u.Memory.MinimumAddress.QuadPart,
335                                    IoDesc->u.Memory.MaximumAddress.QuadPart,
336                                    IoDesc->u.Memory.Length);
337                         }
338                         break;
339 
340                     case CmResourceTypeBusNumber:
341                         /* Make sure the length matches and it satisfies our bus number range */
342                         if (CmDesc->u.BusNumber.Length == IoDesc->u.BusNumber.Length &&
343                             CmDesc->u.BusNumber.Start >= IoDesc->u.BusNumber.MinBusNumber &&
344                             CmDesc->u.BusNumber.Start + CmDesc->u.BusNumber.Length - 1 <= IoDesc->u.BusNumber.MaxBusNumber)
345                         {
346                             /* Found it */
347                             Matched = TRUE;
348                         }
349                         else
350                         {
351                             DPRINT("Bus Number - Not a match! 0x%x with length 0x%x not inside 0x%x to 0x%x with length 0x%x\n",
352                                    CmDesc->u.BusNumber.Start,
353                                    CmDesc->u.BusNumber.Length,
354                                    IoDesc->u.BusNumber.MinBusNumber,
355                                    IoDesc->u.BusNumber.MaxBusNumber,
356                                    IoDesc->u.BusNumber.Length);
357                         }
358                         break;
359 
360                     case CmResourceTypeDma:
361                         /* Make sure it fits in our channel range */
362                         if (CmDesc->u.Dma.Channel >= IoDesc->u.Dma.MinimumChannel &&
363                             CmDesc->u.Dma.Channel <= IoDesc->u.Dma.MaximumChannel)
364                         {
365                             /* Found it */
366                             Matched = TRUE;
367                         }
368                         else
369                         {
370                             DPRINT("DMA - Not a match! 0x%x not inside 0x%x to 0x%x\n",
371                                    CmDesc->u.Dma.Channel,
372                                    IoDesc->u.Dma.MinimumChannel,
373                                    IoDesc->u.Dma.MaximumChannel);
374                         }
375                         break;
376 
377                     default:
378                         /* Other stuff is fine */
379                         Matched = TRUE;
380                         break;
381                 }
382             }
383 
384             /* Check if we found a matching descriptor */
385             if (!Matched)
386             {
387                 PCM_RESOURCE_LIST NewList;
388                 CM_PARTIAL_RESOURCE_DESCRIPTOR NewDesc;
389                 PCM_PARTIAL_RESOURCE_DESCRIPTOR DescPtr;
390                 BOOLEAN FoundResource = TRUE;
391 
392                 /* Setup the new CM descriptor */
393                 NewDesc.Type = IoDesc->Type;
394                 NewDesc.Flags = IoDesc->Flags;
395                 NewDesc.ShareDisposition = IoDesc->ShareDisposition;
396 
397                 /* Let'se see if we can find a resource to satisfy this */
398                 switch (IoDesc->Type)
399                 {
400                     case CmResourceTypeInterrupt:
401                         /* Find an available interrupt */
402                         if (!IopFindInterruptResource(IoDesc, &NewDesc))
403                         {
404                             DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
405                                     IoDesc->u.Interrupt.MinimumVector, IoDesc->u.Interrupt.MaximumVector);
406 
407                             FoundResource = FALSE;
408                         }
409                         break;
410 
411                     case CmResourceTypePort:
412                         /* Find an available port range */
413                         if (!IopFindPortResource(IoDesc, &NewDesc))
414                         {
415                             DPRINT1("Failed to find an available port resource (0x%I64x to 0x%I64x length: 0x%x)\n",
416                                     IoDesc->u.Port.MinimumAddress.QuadPart, IoDesc->u.Port.MaximumAddress.QuadPart,
417                                     IoDesc->u.Port.Length);
418 
419                             FoundResource = FALSE;
420                         }
421                         break;
422 
423                     case CmResourceTypeMemory:
424                         /* Find an available memory range */
425                         if (!IopFindMemoryResource(IoDesc, &NewDesc))
426                         {
427                             DPRINT1("Failed to find an available memory resource (0x%I64x to 0x%I64x length: 0x%x)\n",
428                                     IoDesc->u.Memory.MinimumAddress.QuadPart, IoDesc->u.Memory.MaximumAddress.QuadPart,
429                                     IoDesc->u.Memory.Length);
430 
431                             FoundResource = FALSE;
432                         }
433                         break;
434 
435                     case CmResourceTypeBusNumber:
436                         /* Find an available bus address range */
437                         if (!IopFindBusNumberResource(IoDesc, &NewDesc))
438                         {
439                             DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
440                                     IoDesc->u.BusNumber.MinBusNumber, IoDesc->u.BusNumber.MaxBusNumber,
441                                     IoDesc->u.BusNumber.Length);
442 
443                             FoundResource = FALSE;
444                         }
445                         break;
446 
447                     case CmResourceTypeDma:
448                         /* Find an available DMA channel */
449                         if (!IopFindDmaResource(IoDesc, &NewDesc))
450                         {
451                             DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
452                                     IoDesc->u.Dma.MinimumChannel, IoDesc->u.Dma.MaximumChannel);
453 
454                             FoundResource = FALSE;
455                         }
456                         break;
457 
458                     default:
459                         DPRINT1("Unsupported resource type: %x\n", IoDesc->Type);
460                         FoundResource = FALSE;
461                         break;
462                 }
463 
464                 /* Check if it's missing and required */
465                 if (!FoundResource && IoDesc->Option == 0)
466                 {
467                     /* Break out of this loop and try the next list */
468                     DPRINT1("Unable to satisfy required resource in list %lu\n", i);
469                     break;
470                 }
471                 else if (!FoundResource)
472                 {
473                     /* Try an alternate for this preferred descriptor */
474                     AlternateRequired = TRUE;
475                     continue;
476                 }
477                 else
478                 {
479                     /* Move on to the next preferred or required descriptor after this one */
480                     AlternateRequired = FALSE;
481                 }
482 
483                 /* Figure out what we need */
484                 if (PartialList == NULL)
485                 {
486                     /* We need a new list */
487                     NewList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST));
488                     if (!NewList)
489                         return STATUS_NO_MEMORY;
490 
491                     /* Set it up */
492                     NewList->Count = 1;
493                     NewList->List[0].InterfaceType = RequirementsList->InterfaceType;
494                     NewList->List[0].BusNumber = RequirementsList->BusNumber;
495                     NewList->List[0].PartialResourceList.Version = 1;
496                     NewList->List[0].PartialResourceList.Revision = 1;
497                     NewList->List[0].PartialResourceList.Count = 1;
498 
499                     /* Set our pointer */
500                     DescPtr = &NewList->List[0].PartialResourceList.PartialDescriptors[0];
501                 }
502                 else
503                 {
504                     /* Allocate the new larger list */
505                     NewList = ExAllocatePool(PagedPool, PnpDetermineResourceListSize(*ResourceList) + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
506                     if (!NewList)
507                         return STATUS_NO_MEMORY;
508 
509                     /* Copy the old stuff back */
510                     RtlCopyMemory(NewList, *ResourceList, PnpDetermineResourceListSize(*ResourceList));
511 
512                     /* Set our pointer */
513                     DescPtr = &NewList->List[0].PartialResourceList.PartialDescriptors[NewList->List[0].PartialResourceList.Count];
514 
515                     /* Increment the descriptor count */
516                     NewList->List[0].PartialResourceList.Count++;
517 
518                     /* Free the old list */
519                     ExFreePool(*ResourceList);
520                 }
521 
522                 /* Copy the descriptor in */
523                 *DescPtr = NewDesc;
524 
525                 /* Store the new list */
526                 *ResourceList = NewList;
527             }
528         }
529 
530         /* Check if we need an alternate with no resources left */
531         if (AlternateRequired)
532         {
533             DPRINT1("Unable to satisfy preferred resource or alternates in list %lu\n", i);
534 
535             /* Try the next alternate list */
536             continue;
537         }
538 
539         /* We're done because we satisfied one of the alternate lists */
540         return STATUS_SUCCESS;
541     }
542 
543     /* We ran out of alternates */
544     DPRINT1("Out of alternate lists!\n");
545 
546     /* Free the list */
547     if (*ResourceList)
548     {
549         ExFreePool(*ResourceList);
550         *ResourceList = NULL;
551     }
552 
553     /* Fail */
554     return STATUS_CONFLICTING_ADDRESSES;
555 }
556 
557 static
558 BOOLEAN
IopCheckResourceDescriptor(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc,IN PCM_RESOURCE_LIST ResourceList,IN BOOLEAN Silent,OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)559 IopCheckResourceDescriptor(
560     IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc,
561     IN PCM_RESOURCE_LIST ResourceList,
562     IN BOOLEAN Silent,
563     OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
564 {
565     ULONG i, ii;
566     BOOLEAN Result = FALSE;
567     PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
568 
569     FullDescriptor = &ResourceList->List[0];
570     for (i = 0; i < ResourceList->Count; i++)
571     {
572         PCM_PARTIAL_RESOURCE_LIST ResList = &FullDescriptor->PartialResourceList;
573         FullDescriptor = CmiGetNextResourceDescriptor(FullDescriptor);
574 
575         for (ii = 0; ii < ResList->Count; ii++)
576         {
577             /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific),
578                but only one is allowed and it must be the last one in the list! */
579             PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList->PartialDescriptors[ii];
580 
581             /* We don't care about shared resources */
582             if (ResDesc->ShareDisposition == CmResourceShareShared &&
583                 ResDesc2->ShareDisposition == CmResourceShareShared)
584                 continue;
585 
586             /* Make sure we're comparing the same types */
587             if (ResDesc->Type != ResDesc2->Type)
588                 continue;
589 
590             switch (ResDesc->Type)
591             {
592                 case CmResourceTypeMemory:
593                 {
594                     /* NOTE: ranges are in a form [x1;x2) */
595                     UINT64 rStart = (UINT64)ResDesc->u.Memory.Start.QuadPart;
596                     UINT64 rEnd = (UINT64)ResDesc->u.Memory.Start.QuadPart
597                                   + ResDesc->u.Memory.Length;
598                     UINT64 r2Start = (UINT64)ResDesc2->u.Memory.Start.QuadPart;
599                     UINT64 r2End = (UINT64)ResDesc2->u.Memory.Start.QuadPart
600                                    + ResDesc2->u.Memory.Length;
601 
602                     if (rStart < r2End && r2Start < rEnd)
603                     {
604                         if (!Silent)
605                         {
606                             DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
607                                     rStart, rEnd, r2Start, r2End);
608                         }
609 
610                         Result = TRUE;
611 
612                         goto ByeBye;
613                     }
614                     break;
615                 }
616                 case CmResourceTypePort:
617                 {
618                     /* NOTE: ranges are in a form [x1;x2) */
619                     UINT64 rStart = (UINT64)ResDesc->u.Port.Start.QuadPart;
620                     UINT64 rEnd = (UINT64)ResDesc->u.Port.Start.QuadPart
621                                   + ResDesc->u.Port.Length;
622                     UINT64 r2Start = (UINT64)ResDesc2->u.Port.Start.QuadPart;
623                     UINT64 r2End = (UINT64)ResDesc2->u.Port.Start.QuadPart
624                                    + ResDesc2->u.Port.Length;
625 
626                     if (rStart < r2End && r2Start < rEnd)
627                     {
628                         if (!Silent)
629                         {
630                             DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
631                                     rStart, rEnd, r2Start, r2End);
632                         }
633 
634                         Result = TRUE;
635 
636                         goto ByeBye;
637                     }
638                     break;
639                 }
640                 case CmResourceTypeInterrupt:
641                 {
642                     if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector)
643                     {
644                         if (!Silent)
645                         {
646                             DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
647                                     ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level,
648                                     ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level);
649                         }
650 
651                         Result = TRUE;
652 
653                         goto ByeBye;
654                     }
655                     break;
656                 }
657                 case CmResourceTypeBusNumber:
658                 {
659                     /* NOTE: ranges are in a form [x1;x2) */
660                     UINT32 rStart = ResDesc->u.BusNumber.Start;
661                     UINT32 rEnd = ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length;
662                     UINT32 r2Start = ResDesc2->u.BusNumber.Start;
663                     UINT32 r2End = ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length;
664 
665                     if (rStart < r2End && r2Start < rEnd)
666                     {
667                         if (!Silent)
668                         {
669                             DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
670                                     rStart, rEnd, r2Start, r2End);
671                         }
672 
673                         Result = TRUE;
674 
675                         goto ByeBye;
676                     }
677                     break;
678                 }
679                 case CmResourceTypeDma:
680                 {
681                     if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel)
682                     {
683                         if (!Silent)
684                         {
685                             DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
686                                     ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port,
687                                     ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port);
688                         }
689 
690                         Result = TRUE;
691 
692                         goto ByeBye;
693                     }
694                     break;
695                 }
696             }
697         }
698     }
699 
700 ByeBye:
701 
702     if (Result && ConflictingDescriptor)
703     {
704         RtlCopyMemory(ConflictingDescriptor,
705                       ResDesc,
706                       sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
707     }
708 
709     // Hacked, because after fixing resource list parsing
710     // we actually detect resource conflicts
711     return Silent ? Result : FALSE; // Result;
712 }
713 
714 static
715 NTSTATUS
IopUpdateControlKeyWithResources(IN PDEVICE_NODE DeviceNode)716 IopUpdateControlKeyWithResources(
717     IN PDEVICE_NODE DeviceNode)
718 {
719     UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
720     UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
721     UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"AllocConfig");
722     HANDLE EnumKey, InstanceKey, ControlKey;
723     NTSTATUS Status;
724     OBJECT_ATTRIBUTES ObjectAttributes;
725 
726     /* Open the Enum key */
727     Status = IopOpenRegistryKeyEx(&EnumKey, NULL, &EnumRoot, KEY_ENUMERATE_SUB_KEYS);
728     if (!NT_SUCCESS(Status))
729         return Status;
730 
731     /* Open the instance key (eg. Root\PNP0A03) */
732     Status = IopOpenRegistryKeyEx(&InstanceKey, EnumKey, &DeviceNode->InstancePath, KEY_ENUMERATE_SUB_KEYS);
733     ZwClose(EnumKey);
734 
735     if (!NT_SUCCESS(Status))
736         return Status;
737 
738     /* Create/Open the Control key */
739     InitializeObjectAttributes(&ObjectAttributes,
740                                &Control,
741                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
742                                InstanceKey,
743                                NULL);
744     Status = ZwCreateKey(&ControlKey,
745                          KEY_SET_VALUE,
746                          &ObjectAttributes,
747                          0,
748                          NULL,
749                          REG_OPTION_VOLATILE,
750                          NULL);
751     ZwClose(InstanceKey);
752 
753     if (!NT_SUCCESS(Status))
754         return Status;
755 
756     /* Write the resource list */
757     Status = ZwSetValueKey(ControlKey,
758                            &ValueName,
759                            0,
760                            REG_RESOURCE_LIST,
761                            DeviceNode->ResourceList,
762                            PnpDetermineResourceListSize(DeviceNode->ResourceList));
763     ZwClose(ControlKey);
764 
765     if (!NT_SUCCESS(Status))
766         return Status;
767 
768     return STATUS_SUCCESS;
769 }
770 
771 static
772 NTSTATUS
IopFilterResourceRequirements(IN PDEVICE_NODE DeviceNode)773 IopFilterResourceRequirements(
774     IN PDEVICE_NODE DeviceNode)
775 {
776     IO_STACK_LOCATION Stack;
777     IO_STATUS_BLOCK IoStatusBlock;
778     NTSTATUS Status;
779 
780     DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
781 
782     Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
783     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
784                                &IoStatusBlock,
785                                IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
786                                &Stack);
787     if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
788     {
789         DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
790         return Status;
791     }
792     else if (NT_SUCCESS(Status) && IoStatusBlock.Information)
793     {
794         DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
795     }
796 
797     return STATUS_SUCCESS;
798 }
799 
800 
801 NTSTATUS
IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode,PWCHAR Level1Key,PWCHAR Level2Key)802 IopUpdateResourceMap(
803     IN PDEVICE_NODE DeviceNode,
804     PWCHAR Level1Key,
805     PWCHAR Level2Key)
806 {
807     NTSTATUS Status;
808     ULONG Disposition;
809     HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey;
810     UNICODE_STRING KeyName;
811     OBJECT_ATTRIBUTES ObjectAttributes;
812 
813     RtlInitUnicodeString(&KeyName,
814                          L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
815     InitializeObjectAttributes(&ObjectAttributes,
816                                &KeyName,
817                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
818                                NULL,
819                                NULL);
820     Status = ZwCreateKey(&ResourceMapKey,
821                          KEY_ALL_ACCESS,
822                          &ObjectAttributes,
823                          0,
824                          NULL,
825                          REG_OPTION_VOLATILE,
826                          &Disposition);
827     if (!NT_SUCCESS(Status))
828         return Status;
829 
830     RtlInitUnicodeString(&KeyName, Level1Key);
831     InitializeObjectAttributes(&ObjectAttributes,
832                                &KeyName,
833                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
834                                ResourceMapKey,
835                                NULL);
836     Status = ZwCreateKey(&PnpMgrLevel1,
837                          KEY_ALL_ACCESS,
838                          &ObjectAttributes,
839                          0,
840                          NULL,
841                          REG_OPTION_VOLATILE,
842                          &Disposition);
843     ZwClose(ResourceMapKey);
844     if (!NT_SUCCESS(Status))
845         return Status;
846 
847     RtlInitUnicodeString(&KeyName, Level2Key);
848     InitializeObjectAttributes(&ObjectAttributes,
849                                &KeyName,
850                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
851                                PnpMgrLevel1,
852                                NULL);
853     Status = ZwCreateKey(&PnpMgrLevel2,
854                          KEY_ALL_ACCESS,
855                          &ObjectAttributes,
856                          0,
857                          NULL,
858                          REG_OPTION_VOLATILE,
859                          &Disposition);
860     ZwClose(PnpMgrLevel1);
861     if (!NT_SUCCESS(Status))
862         return Status;
863 
864     if (DeviceNode->ResourceList)
865     {
866         UNICODE_STRING NameU;
867         UNICODE_STRING RawSuffix, TranslatedSuffix;
868         ULONG OldLength = 0;
869 
870         ASSERT(DeviceNode->ResourceListTranslated);
871 
872         RtlInitUnicodeString(&TranslatedSuffix, L".Translated");
873         RtlInitUnicodeString(&RawSuffix, L".Raw");
874 
875         Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
876                                      DevicePropertyPhysicalDeviceObjectName,
877                                      0,
878                                      NULL,
879                                      &OldLength);
880         if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
881         {
882             ASSERT(OldLength);
883 
884             NameU.Buffer = ExAllocatePool(PagedPool, OldLength + TranslatedSuffix.Length);
885             if (!NameU.Buffer)
886             {
887                 ZwClose(PnpMgrLevel2);
888                 return STATUS_INSUFFICIENT_RESOURCES;
889             }
890 
891             NameU.Length = 0;
892             NameU.MaximumLength = (USHORT)OldLength + TranslatedSuffix.Length;
893 
894             Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
895                                          DevicePropertyPhysicalDeviceObjectName,
896                                          NameU.MaximumLength,
897                                          NameU.Buffer,
898                                          &OldLength);
899             if (!NT_SUCCESS(Status))
900             {
901                 ZwClose(PnpMgrLevel2);
902                 ExFreePool(NameU.Buffer);
903                 return Status;
904             }
905         }
906         else if (!NT_SUCCESS(Status))
907         {
908             /* Some failure */
909             ZwClose(PnpMgrLevel2);
910             return Status;
911         }
912         else
913         {
914             /* This should never happen */
915             ASSERT(FALSE);
916         }
917 
918         NameU.Length = (USHORT)OldLength - sizeof(UNICODE_NULL); /* Remove final NULL */
919 
920         RtlAppendUnicodeStringToString(&NameU, &RawSuffix);
921 
922         Status = ZwSetValueKey(PnpMgrLevel2,
923                                &NameU,
924                                0,
925                                REG_RESOURCE_LIST,
926                                DeviceNode->ResourceList,
927                                PnpDetermineResourceListSize(DeviceNode->ResourceList));
928         if (!NT_SUCCESS(Status))
929         {
930             ZwClose(PnpMgrLevel2);
931             ExFreePool(NameU.Buffer);
932             return Status;
933         }
934 
935         /* "Remove" the suffix by setting the length back to what it used to be */
936         NameU.Length = (USHORT)OldLength - sizeof(UNICODE_NULL); /* Remove final NULL */
937 
938         RtlAppendUnicodeStringToString(&NameU, &TranslatedSuffix);
939 
940         Status = ZwSetValueKey(PnpMgrLevel2,
941                                &NameU,
942                                0,
943                                REG_RESOURCE_LIST,
944                                DeviceNode->ResourceListTranslated,
945                                PnpDetermineResourceListSize(DeviceNode->ResourceListTranslated));
946         ZwClose(PnpMgrLevel2);
947         ExFreePool(NameU.Buffer);
948 
949         if (!NT_SUCCESS(Status))
950             return Status;
951     }
952     else
953     {
954         ZwClose(PnpMgrLevel2);
955     }
956 
957     return STATUS_SUCCESS;
958 }
959 
960 NTSTATUS
IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode)961 IopUpdateResourceMapForPnPDevice(
962     IN PDEVICE_NODE DeviceNode)
963 {
964     return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager");
965 }
966 
967 static
968 NTSTATUS
IopTranslateDeviceResources(IN PDEVICE_NODE DeviceNode)969 IopTranslateDeviceResources(
970    IN PDEVICE_NODE DeviceNode)
971 {
972    PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
973    PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
974    PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
975    ULONG i, j, ListSize;
976    NTSTATUS Status;
977 
978    if (!DeviceNode->ResourceList)
979    {
980       DeviceNode->ResourceListTranslated = NULL;
981       return STATUS_SUCCESS;
982    }
983 
984    /* That's easy to translate a resource list. Just copy the
985     * untranslated one and change few fields in the copy
986     */
987    ListSize = PnpDetermineResourceListSize(DeviceNode->ResourceList);
988 
989    DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, ListSize);
990    if (!DeviceNode->ResourceListTranslated)
991    {
992       Status = STATUS_NO_MEMORY;
993       goto cleanup;
994    }
995    RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, ListSize);
996 
997    FullDescriptor = &DeviceNode->ResourceList->List[0];
998    for (i = 0; i < DeviceNode->ResourceList->Count; i++)
999    {
1000       pPartialResourceList = &FullDescriptor->PartialResourceList;
1001       FullDescriptor = CmiGetNextResourceDescriptor(FullDescriptor);
1002 
1003       for (j = 0; j < pPartialResourceList->Count; j++)
1004       {
1005         /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific),
1006            but only one is allowed and it must be the last one in the list! */
1007          DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
1008 
1009          /* Calculate the location of the translated resource descriptor */
1010          DescriptorTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)(
1011              (PUCHAR)DeviceNode->ResourceListTranslated +
1012              ((PUCHAR)DescriptorRaw - (PUCHAR)DeviceNode->ResourceList));
1013 
1014          switch (DescriptorRaw->Type)
1015          {
1016             case CmResourceTypePort:
1017             {
1018                ULONG AddressSpace = 1; /* IO space */
1019                if (!HalTranslateBusAddress(
1020                   DeviceNode->ResourceList->List[i].InterfaceType,
1021                   DeviceNode->ResourceList->List[i].BusNumber,
1022                   DescriptorRaw->u.Port.Start,
1023                   &AddressSpace,
1024                   &DescriptorTranslated->u.Port.Start))
1025                {
1026                   Status = STATUS_UNSUCCESSFUL;
1027                   DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw->u.Port.Start.QuadPart);
1028                   goto cleanup;
1029                }
1030 
1031                if (AddressSpace == 0)
1032                {
1033                    DPRINT1("Guessed incorrect address space: 1 -> 0\n");
1034 
1035                    /* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are
1036                     * invalid for this state but I'm not 100% sure */
1037                    DescriptorRaw->Flags =
1038                    DescriptorTranslated->Flags = CM_RESOURCE_PORT_MEMORY;
1039                }
1040                break;
1041             }
1042             case CmResourceTypeInterrupt:
1043             {
1044                KIRQL Irql;
1045                DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
1046                   DeviceNode->ResourceList->List[i].InterfaceType,
1047                   DeviceNode->ResourceList->List[i].BusNumber,
1048                   DescriptorRaw->u.Interrupt.Level,
1049                   DescriptorRaw->u.Interrupt.Vector,
1050                   &Irql,
1051                   &DescriptorTranslated->u.Interrupt.Affinity);
1052                DescriptorTranslated->u.Interrupt.Level = Irql;
1053                if (!DescriptorTranslated->u.Interrupt.Vector)
1054                {
1055                    Status = STATUS_UNSUCCESSFUL;
1056                    DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw->u.Interrupt.Vector,
1057                                                                                                    DescriptorRaw->u.Interrupt.Level);
1058                    goto cleanup;
1059                }
1060                break;
1061             }
1062             case CmResourceTypeMemory:
1063             {
1064                ULONG AddressSpace = 0; /* Memory space */
1065                if (!HalTranslateBusAddress(
1066                   DeviceNode->ResourceList->List[i].InterfaceType,
1067                   DeviceNode->ResourceList->List[i].BusNumber,
1068                   DescriptorRaw->u.Memory.Start,
1069                   &AddressSpace,
1070                   &DescriptorTranslated->u.Memory.Start))
1071                {
1072                   Status = STATUS_UNSUCCESSFUL;
1073                   DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw->u.Memory.Start.QuadPart);
1074                   goto cleanup;
1075                }
1076 
1077                if (AddressSpace != 0)
1078                {
1079                    DPRINT1("Guessed incorrect address space: 0 -> 1\n");
1080 
1081                    /* This should never happen for memory space */
1082                    ASSERT(FALSE);
1083                }
1084             }
1085 
1086             case CmResourceTypeDma:
1087             case CmResourceTypeBusNumber:
1088             case CmResourceTypeDevicePrivate:
1089             case CmResourceTypeDeviceSpecific:
1090                /* Nothing to do */
1091                break;
1092             default:
1093                DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
1094                Status = STATUS_NOT_IMPLEMENTED;
1095                goto cleanup;
1096          }
1097       }
1098    }
1099    return STATUS_SUCCESS;
1100 
1101 cleanup:
1102    /* Yes! Also delete ResourceList because ResourceList and
1103     * ResourceListTranslated should be a pair! */
1104    ExFreePool(DeviceNode->ResourceList);
1105    DeviceNode->ResourceList = NULL;
1106    if (DeviceNode->ResourceListTranslated)
1107    {
1108       ExFreePool(DeviceNode->ResourceListTranslated);
1109       DeviceNode->ResourceList = NULL;
1110    }
1111    return Status;
1112 }
1113 
1114 NTSTATUS
1115 NTAPI
IopAssignDeviceResources(IN PDEVICE_NODE DeviceNode)1116 IopAssignDeviceResources(
1117    IN PDEVICE_NODE DeviceNode)
1118 {
1119    NTSTATUS Status;
1120    ULONG ListSize;
1121 
1122    Status = IopFilterResourceRequirements(DeviceNode);
1123    if (!NT_SUCCESS(Status))
1124        goto ByeBye;
1125 
1126    if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
1127    {
1128       /* No resource needed for this device */
1129       DeviceNode->ResourceList = NULL;
1130       DeviceNode->ResourceListTranslated = NULL;
1131       PiSetDevNodeState(DeviceNode, DeviceNodeResourcesAssigned);
1132       DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
1133 
1134       return STATUS_SUCCESS;
1135    }
1136 
1137    if (DeviceNode->BootResources)
1138    {
1139        ListSize = PnpDetermineResourceListSize(DeviceNode->BootResources);
1140 
1141        DeviceNode->ResourceList = ExAllocatePool(PagedPool, ListSize);
1142        if (!DeviceNode->ResourceList)
1143        {
1144            Status = STATUS_NO_MEMORY;
1145            goto ByeBye;
1146        }
1147 
1148        RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, ListSize);
1149 
1150        Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1151        if (!NT_SUCCESS(Status))
1152        {
1153            DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
1154            ExFreePool(DeviceNode->ResourceList);
1155            DeviceNode->ResourceList = NULL;
1156        }
1157    }
1158    else
1159    {
1160        /* We'll make this from the requirements */
1161        DeviceNode->ResourceList = NULL;
1162    }
1163 
1164    /* No resources requirements */
1165    if (!DeviceNode->ResourceRequirements)
1166        goto Finish;
1167 
1168    /* Call HAL to fixup our resource requirements list */
1169    HalAdjustResourceList(&DeviceNode->ResourceRequirements);
1170 
1171    /* Add resource requirements that aren't in the list we already got */
1172    Status = IopFixupResourceListWithRequirements(DeviceNode->ResourceRequirements,
1173                                                  &DeviceNode->ResourceList);
1174    if (!NT_SUCCESS(Status))
1175    {
1176        DPRINT1("Failed to fixup a resource list from supplied resources for %wZ\n", &DeviceNode->InstancePath);
1177        DeviceNode->Problem = CM_PROB_NORMAL_CONFLICT;
1178        goto ByeBye;
1179    }
1180 
1181    /* IopFixupResourceListWithRequirements should NEVER give us a conflicting list */
1182    ASSERT(IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL) != STATUS_CONFLICTING_ADDRESSES);
1183 
1184 Finish:
1185    Status = IopTranslateDeviceResources(DeviceNode);
1186    if (!NT_SUCCESS(Status))
1187    {
1188        DeviceNode->Problem = CM_PROB_TRANSLATION_FAILED;
1189        DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode->InstancePath);
1190        goto ByeBye;
1191    }
1192 
1193    Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
1194    if (!NT_SUCCESS(Status))
1195        goto ByeBye;
1196 
1197    Status = IopUpdateControlKeyWithResources(DeviceNode);
1198    if (!NT_SUCCESS(Status))
1199        goto ByeBye;
1200 
1201    PiSetDevNodeState(DeviceNode, DeviceNodeResourcesAssigned);
1202 
1203    return STATUS_SUCCESS;
1204 
1205 ByeBye:
1206    if (DeviceNode->ResourceList)
1207    {
1208       ExFreePool(DeviceNode->ResourceList);
1209       DeviceNode->ResourceList = NULL;
1210    }
1211 
1212    DeviceNode->ResourceListTranslated = NULL;
1213 
1214    return Status;
1215 }
1216 
1217 static
1218 BOOLEAN
IopCheckForResourceConflict(IN PCM_RESOURCE_LIST ResourceList1,IN PCM_RESOURCE_LIST ResourceList2,IN BOOLEAN Silent,OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)1219 IopCheckForResourceConflict(
1220    IN PCM_RESOURCE_LIST ResourceList1,
1221    IN PCM_RESOURCE_LIST ResourceList2,
1222    IN BOOLEAN Silent,
1223    OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1224 {
1225    ULONG i, ii;
1226    BOOLEAN Result = FALSE;
1227    PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
1228 
1229    FullDescriptor = &ResourceList1->List[0];
1230    for (i = 0; i < ResourceList1->Count; i++)
1231    {
1232       PCM_PARTIAL_RESOURCE_LIST ResList = &FullDescriptor->PartialResourceList;
1233       FullDescriptor = CmiGetNextResourceDescriptor(FullDescriptor);
1234 
1235       for (ii = 0; ii < ResList->Count; ii++)
1236       {
1237         /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific),
1238            but only one is allowed and it must be the last one in the list! */
1239          PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
1240 
1241          Result = IopCheckResourceDescriptor(ResDesc,
1242                                              ResourceList2,
1243                                              Silent,
1244                                              ConflictingDescriptor);
1245          if (Result) goto ByeBye;
1246       }
1247    }
1248 
1249 ByeBye:
1250 
1251    return Result;
1252 }
1253 
1254 NTSTATUS NTAPI
IopDetectResourceConflict(IN PCM_RESOURCE_LIST ResourceList,IN BOOLEAN Silent,OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)1255 IopDetectResourceConflict(
1256    IN PCM_RESOURCE_LIST ResourceList,
1257    IN BOOLEAN Silent,
1258    OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1259 {
1260    OBJECT_ATTRIBUTES ObjectAttributes;
1261    UNICODE_STRING KeyName;
1262    HANDLE ResourceMapKey = NULL, ChildKey2 = NULL, ChildKey3 = NULL;
1263    ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
1264    PKEY_BASIC_INFORMATION KeyInformation;
1265    PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
1266    PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
1267    ULONG ChildKeyIndex1 = 0, ChildKeyIndex2, ChildKeyIndex3;
1268    NTSTATUS Status;
1269 
1270    RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1271    InitializeObjectAttributes(&ObjectAttributes,
1272                               &KeyName,
1273                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1274                               NULL,
1275                               NULL);
1276    Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1277    if (!NT_SUCCESS(Status))
1278    {
1279       /* The key is missing which means we are the first device */
1280       return STATUS_SUCCESS;
1281    }
1282 
1283    while (TRUE)
1284    {
1285       Status = ZwEnumerateKey(ResourceMapKey,
1286                               ChildKeyIndex1,
1287                               KeyBasicInformation,
1288                               NULL,
1289                               0,
1290                               &RequiredLength);
1291       if (Status == STATUS_NO_MORE_ENTRIES)
1292           break;
1293       else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1294       {
1295           KeyInformationLength = RequiredLength;
1296           KeyInformation = ExAllocatePoolWithTag(PagedPool,
1297                                                  KeyInformationLength,
1298                                                  TAG_IO);
1299           if (!KeyInformation)
1300           {
1301               Status = STATUS_INSUFFICIENT_RESOURCES;
1302               goto cleanup;
1303           }
1304 
1305           Status = ZwEnumerateKey(ResourceMapKey,
1306                                   ChildKeyIndex1,
1307                                   KeyBasicInformation,
1308                                   KeyInformation,
1309                                   KeyInformationLength,
1310                                   &RequiredLength);
1311       }
1312       else
1313          goto cleanup;
1314       ChildKeyIndex1++;
1315       if (!NT_SUCCESS(Status))
1316       {
1317           ExFreePoolWithTag(KeyInformation, TAG_IO);
1318           goto cleanup;
1319       }
1320 
1321       KeyName.Buffer = KeyInformation->Name;
1322       KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
1323       InitializeObjectAttributes(&ObjectAttributes,
1324                                  &KeyName,
1325                                  OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1326                                  ResourceMapKey,
1327                                  NULL);
1328       Status = ZwOpenKey(&ChildKey2,
1329                          KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
1330                          &ObjectAttributes);
1331       ExFreePoolWithTag(KeyInformation, TAG_IO);
1332       if (!NT_SUCCESS(Status))
1333           goto cleanup;
1334 
1335       ChildKeyIndex2 = 0;
1336       while (TRUE)
1337       {
1338           Status = ZwEnumerateKey(ChildKey2,
1339                                   ChildKeyIndex2,
1340                                   KeyBasicInformation,
1341                                   NULL,
1342                                   0,
1343                                   &RequiredLength);
1344           if (Status == STATUS_NO_MORE_ENTRIES)
1345               break;
1346           else if (Status == STATUS_BUFFER_TOO_SMALL)
1347           {
1348               KeyInformationLength = RequiredLength;
1349               KeyInformation = ExAllocatePoolWithTag(PagedPool,
1350                                                      KeyInformationLength,
1351                                                      TAG_IO);
1352               if (!KeyInformation)
1353               {
1354                   Status = STATUS_INSUFFICIENT_RESOURCES;
1355                   goto cleanup;
1356               }
1357 
1358               Status = ZwEnumerateKey(ChildKey2,
1359                                       ChildKeyIndex2,
1360                                       KeyBasicInformation,
1361                                       KeyInformation,
1362                                       KeyInformationLength,
1363                                       &RequiredLength);
1364           }
1365           else
1366               goto cleanup;
1367           ChildKeyIndex2++;
1368           if (!NT_SUCCESS(Status))
1369           {
1370               ExFreePoolWithTag(KeyInformation, TAG_IO);
1371               goto cleanup;
1372           }
1373 
1374           KeyName.Buffer = KeyInformation->Name;
1375           KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
1376           InitializeObjectAttributes(&ObjectAttributes,
1377                                      &KeyName,
1378                                      OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1379                                      ChildKey2,
1380                                      NULL);
1381           Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
1382           ExFreePoolWithTag(KeyInformation, TAG_IO);
1383           if (!NT_SUCCESS(Status))
1384               goto cleanup;
1385 
1386           ChildKeyIndex3 = 0;
1387           while (TRUE)
1388           {
1389               Status = ZwEnumerateValueKey(ChildKey3,
1390                                            ChildKeyIndex3,
1391                                            KeyValuePartialInformation,
1392                                            NULL,
1393                                            0,
1394                                            &RequiredLength);
1395               if (Status == STATUS_NO_MORE_ENTRIES)
1396                   break;
1397               else if (Status == STATUS_BUFFER_TOO_SMALL)
1398               {
1399                   KeyValueInformationLength = RequiredLength;
1400                   KeyValueInformation = ExAllocatePoolWithTag(PagedPool,
1401                                                               KeyValueInformationLength,
1402                                                               TAG_IO);
1403                   if (!KeyValueInformation)
1404                   {
1405                       Status = STATUS_INSUFFICIENT_RESOURCES;
1406                       goto cleanup;
1407                   }
1408 
1409                   Status = ZwEnumerateValueKey(ChildKey3,
1410                                                ChildKeyIndex3,
1411                                                KeyValuePartialInformation,
1412                                                KeyValueInformation,
1413                                                KeyValueInformationLength,
1414                                                &RequiredLength);
1415               }
1416               else
1417                   goto cleanup;
1418               if (!NT_SUCCESS(Status))
1419               {
1420                   ExFreePoolWithTag(KeyValueInformation, TAG_IO);
1421                   goto cleanup;
1422               }
1423 
1424               Status = ZwEnumerateValueKey(ChildKey3,
1425                                            ChildKeyIndex3,
1426                                            KeyValueBasicInformation,
1427                                            NULL,
1428                                            0,
1429                                            &RequiredLength);
1430               if (Status == STATUS_BUFFER_TOO_SMALL)
1431               {
1432                   KeyNameInformationLength = RequiredLength;
1433                   KeyNameInformation = ExAllocatePoolWithTag(PagedPool,
1434                                                              KeyNameInformationLength + sizeof(WCHAR),
1435                                                              TAG_IO);
1436                   if (!KeyNameInformation)
1437                   {
1438                       Status = STATUS_INSUFFICIENT_RESOURCES;
1439                       goto cleanup;
1440                   }
1441 
1442                   Status = ZwEnumerateValueKey(ChildKey3,
1443                                                ChildKeyIndex3,
1444                                                KeyValueBasicInformation,
1445                                                KeyNameInformation,
1446                                                KeyNameInformationLength,
1447                                                &RequiredLength);
1448               }
1449               else
1450                   goto cleanup;
1451               ChildKeyIndex3++;
1452               if (!NT_SUCCESS(Status))
1453               {
1454                   ExFreePoolWithTag(KeyNameInformation, TAG_IO);
1455                   goto cleanup;
1456               }
1457 
1458               KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
1459 
1460               /* Skip translated entries */
1461               if (wcsstr(KeyNameInformation->Name, L".Translated"))
1462               {
1463                   ExFreePoolWithTag(KeyNameInformation, TAG_IO);
1464                   ExFreePoolWithTag(KeyValueInformation, TAG_IO);
1465                   continue;
1466               }
1467 
1468               ExFreePoolWithTag(KeyNameInformation, TAG_IO);
1469 
1470               if (IopCheckForResourceConflict(ResourceList,
1471                                               (PCM_RESOURCE_LIST)KeyValueInformation->Data,
1472                                               Silent,
1473                                               ConflictingDescriptor))
1474               {
1475                   ExFreePoolWithTag(KeyValueInformation, TAG_IO);
1476                   Status = STATUS_CONFLICTING_ADDRESSES;
1477                   goto cleanup;
1478               }
1479 
1480               ExFreePoolWithTag(KeyValueInformation, TAG_IO);
1481           }
1482       }
1483    }
1484 
1485 cleanup:
1486    if (ResourceMapKey != NULL)
1487        ObCloseHandle(ResourceMapKey, KernelMode);
1488    if (ChildKey2 != NULL)
1489        ObCloseHandle(ChildKey2, KernelMode);
1490    if (ChildKey3 != NULL)
1491        ObCloseHandle(ChildKey3, KernelMode);
1492 
1493    if (Status == STATUS_NO_MORE_ENTRIES)
1494        Status = STATUS_SUCCESS;
1495 
1496    return Status;
1497 }
1498 
1499