xref: /reactos/ntoskrnl/io/pnpmgr/pnpres.c (revision 8a978a17)
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
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
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
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
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
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
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
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
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
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                     if (((ULONGLONG)ResDesc->u.Memory.Start.QuadPart < (ULONGLONG)ResDesc2->u.Memory.Start.QuadPart &&
594                          (ULONGLONG)ResDesc->u.Memory.Start.QuadPart + ResDesc->u.Memory.Length >
595                          (ULONGLONG)ResDesc2->u.Memory.Start.QuadPart) || ((ULONGLONG)ResDesc2->u.Memory.Start.QuadPart <
596                          (ULONGLONG)ResDesc->u.Memory.Start.QuadPart && (ULONGLONG)ResDesc2->u.Memory.Start.QuadPart +
597                          ResDesc2->u.Memory.Length > (ULONGLONG)ResDesc->u.Memory.Start.QuadPart))
598                     {
599                         if (!Silent)
600                         {
601                             DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
602                                     ResDesc->u.Memory.Start.QuadPart, ResDesc->u.Memory.Start.QuadPart +
603                                     ResDesc->u.Memory.Length, ResDesc2->u.Memory.Start.QuadPart,
604                                     ResDesc2->u.Memory.Start.QuadPart + ResDesc2->u.Memory.Length);
605                         }
606 
607                         Result = TRUE;
608 
609                         goto ByeBye;
610                     }
611                     break;
612 
613                 case CmResourceTypePort:
614                     if (((ULONGLONG)ResDesc->u.Port.Start.QuadPart < (ULONGLONG)ResDesc2->u.Port.Start.QuadPart &&
615                          (ULONGLONG)ResDesc->u.Port.Start.QuadPart + ResDesc->u.Port.Length >
616                          (ULONGLONG)ResDesc2->u.Port.Start.QuadPart) || ((ULONGLONG)ResDesc2->u.Port.Start.QuadPart <
617                          (ULONGLONG)ResDesc->u.Port.Start.QuadPart && (ULONGLONG)ResDesc2->u.Port.Start.QuadPart +
618                          ResDesc2->u.Port.Length > (ULONGLONG)ResDesc->u.Port.Start.QuadPart))
619                     {
620                         if (!Silent)
621                         {
622                             DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
623                                     ResDesc->u.Port.Start.QuadPart, ResDesc->u.Port.Start.QuadPart +
624                                     ResDesc->u.Port.Length, ResDesc2->u.Port.Start.QuadPart,
625                                     ResDesc2->u.Port.Start.QuadPart + ResDesc2->u.Port.Length);
626                         }
627 
628                         Result = TRUE;
629 
630                         goto ByeBye;
631                     }
632                     break;
633 
634                 case CmResourceTypeInterrupt:
635                     if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector)
636                     {
637                         if (!Silent)
638                         {
639                             DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
640                                     ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level,
641                                     ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level);
642                         }
643 
644                         Result = TRUE;
645 
646                         goto ByeBye;
647                     }
648                     break;
649 
650                 case CmResourceTypeBusNumber:
651                     if ((ResDesc->u.BusNumber.Start < ResDesc2->u.BusNumber.Start &&
652                          ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length >
653                          ResDesc2->u.BusNumber.Start) || (ResDesc2->u.BusNumber.Start <
654                          ResDesc->u.BusNumber.Start && ResDesc2->u.BusNumber.Start +
655                          ResDesc2->u.BusNumber.Length > ResDesc->u.BusNumber.Start))
656                     {
657                         if (!Silent)
658                         {
659                             DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
660                                     ResDesc->u.BusNumber.Start, ResDesc->u.BusNumber.Start +
661                                     ResDesc->u.BusNumber.Length, ResDesc2->u.BusNumber.Start,
662                                     ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length);
663                         }
664 
665                         Result = TRUE;
666 
667                         goto ByeBye;
668                     }
669                     break;
670 
671                 case CmResourceTypeDma:
672                     if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel)
673                     {
674                         if (!Silent)
675                         {
676                             DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
677                                     ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port,
678                                     ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port);
679                         }
680 
681                         Result = TRUE;
682 
683                         goto ByeBye;
684                     }
685                     break;
686             }
687         }
688     }
689 
690 ByeBye:
691 
692     if (Result && ConflictingDescriptor)
693     {
694         RtlCopyMemory(ConflictingDescriptor,
695                       ResDesc,
696                       sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
697     }
698 
699     // Hacked, because after fixing resource list parsing
700     // we actually detect resource conflicts
701     return Silent ? Result : FALSE; // Result;
702 }
703 
704 static
705 NTSTATUS
706 IopUpdateControlKeyWithResources(
707     IN PDEVICE_NODE DeviceNode)
708 {
709     UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
710     UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
711     UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"AllocConfig");
712     HANDLE EnumKey, InstanceKey, ControlKey;
713     NTSTATUS Status;
714     OBJECT_ATTRIBUTES ObjectAttributes;
715 
716     /* Open the Enum key */
717     Status = IopOpenRegistryKeyEx(&EnumKey, NULL, &EnumRoot, KEY_ENUMERATE_SUB_KEYS);
718     if (!NT_SUCCESS(Status))
719         return Status;
720 
721     /* Open the instance key (eg. Root\PNP0A03) */
722     Status = IopOpenRegistryKeyEx(&InstanceKey, EnumKey, &DeviceNode->InstancePath, KEY_ENUMERATE_SUB_KEYS);
723     ZwClose(EnumKey);
724 
725     if (!NT_SUCCESS(Status))
726         return Status;
727 
728     /* Create/Open the Control key */
729     InitializeObjectAttributes(&ObjectAttributes,
730                                &Control,
731                                OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
732                                InstanceKey,
733                                NULL);
734     Status = ZwCreateKey(&ControlKey,
735                          KEY_SET_VALUE,
736                          &ObjectAttributes,
737                          0,
738                          NULL,
739                          REG_OPTION_VOLATILE,
740                          NULL);
741     ZwClose(InstanceKey);
742 
743     if (!NT_SUCCESS(Status))
744         return Status;
745 
746     /* Write the resource list */
747     Status = ZwSetValueKey(ControlKey,
748                            &ValueName,
749                            0,
750                            REG_RESOURCE_LIST,
751                            DeviceNode->ResourceList,
752                            PnpDetermineResourceListSize(DeviceNode->ResourceList));
753     ZwClose(ControlKey);
754 
755     if (!NT_SUCCESS(Status))
756         return Status;
757 
758     return STATUS_SUCCESS;
759 }
760 
761 static
762 NTSTATUS
763 IopFilterResourceRequirements(
764     IN PDEVICE_NODE DeviceNode)
765 {
766     IO_STACK_LOCATION Stack;
767     IO_STATUS_BLOCK IoStatusBlock;
768     NTSTATUS Status;
769 
770     DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
771 
772     Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
773     Status = IopInitiatePnpIrp(DeviceNode->PhysicalDeviceObject,
774                                &IoStatusBlock,
775                                IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
776                                &Stack);
777     if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
778     {
779         DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
780         return Status;
781     }
782     else if (NT_SUCCESS(Status) && IoStatusBlock.Information)
783     {
784         DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
785     }
786 
787     return STATUS_SUCCESS;
788 }
789 
790 
791 NTSTATUS
792 IopUpdateResourceMap(
793     IN PDEVICE_NODE DeviceNode,
794     PWCHAR Level1Key,
795     PWCHAR Level2Key)
796 {
797     NTSTATUS Status;
798     ULONG Disposition;
799     HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey;
800     UNICODE_STRING KeyName;
801     OBJECT_ATTRIBUTES ObjectAttributes;
802 
803     RtlInitUnicodeString(&KeyName,
804                          L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
805     InitializeObjectAttributes(&ObjectAttributes,
806                                &KeyName,
807                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
808                                NULL,
809                                NULL);
810     Status = ZwCreateKey(&ResourceMapKey,
811                          KEY_ALL_ACCESS,
812                          &ObjectAttributes,
813                          0,
814                          NULL,
815                          REG_OPTION_VOLATILE,
816                          &Disposition);
817     if (!NT_SUCCESS(Status))
818         return Status;
819 
820     RtlInitUnicodeString(&KeyName, Level1Key);
821     InitializeObjectAttributes(&ObjectAttributes,
822                                &KeyName,
823                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
824                                ResourceMapKey,
825                                NULL);
826     Status = ZwCreateKey(&PnpMgrLevel1,
827                          KEY_ALL_ACCESS,
828                          &ObjectAttributes,
829                          0,
830                          NULL,
831                          REG_OPTION_VOLATILE,
832                          &Disposition);
833     ZwClose(ResourceMapKey);
834     if (!NT_SUCCESS(Status))
835         return Status;
836 
837     RtlInitUnicodeString(&KeyName, Level2Key);
838     InitializeObjectAttributes(&ObjectAttributes,
839                                &KeyName,
840                                OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE,
841                                PnpMgrLevel1,
842                                NULL);
843     Status = ZwCreateKey(&PnpMgrLevel2,
844                          KEY_ALL_ACCESS,
845                          &ObjectAttributes,
846                          0,
847                          NULL,
848                          REG_OPTION_VOLATILE,
849                          &Disposition);
850     ZwClose(PnpMgrLevel1);
851     if (!NT_SUCCESS(Status))
852         return Status;
853 
854     if (DeviceNode->ResourceList)
855     {
856         UNICODE_STRING NameU;
857         UNICODE_STRING RawSuffix, TranslatedSuffix;
858         ULONG OldLength = 0;
859 
860         ASSERT(DeviceNode->ResourceListTranslated);
861 
862         RtlInitUnicodeString(&TranslatedSuffix, L".Translated");
863         RtlInitUnicodeString(&RawSuffix, L".Raw");
864 
865         Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
866                                      DevicePropertyPhysicalDeviceObjectName,
867                                      0,
868                                      NULL,
869                                      &OldLength);
870         if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
871         {
872             ASSERT(OldLength);
873 
874             NameU.Buffer = ExAllocatePool(PagedPool, OldLength + TranslatedSuffix.Length);
875             if (!NameU.Buffer)
876             {
877                 ZwClose(PnpMgrLevel2);
878                 return STATUS_INSUFFICIENT_RESOURCES;
879             }
880 
881             NameU.Length = 0;
882             NameU.MaximumLength = (USHORT)OldLength + TranslatedSuffix.Length;
883 
884             Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
885                                          DevicePropertyPhysicalDeviceObjectName,
886                                          NameU.MaximumLength,
887                                          NameU.Buffer,
888                                          &OldLength);
889             if (!NT_SUCCESS(Status))
890             {
891                 ZwClose(PnpMgrLevel2);
892                 ExFreePool(NameU.Buffer);
893                 return Status;
894             }
895         }
896         else if (!NT_SUCCESS(Status))
897         {
898             /* Some failure */
899             ZwClose(PnpMgrLevel2);
900             return Status;
901         }
902         else
903         {
904             /* This should never happen */
905             ASSERT(FALSE);
906         }
907 
908         NameU.Length = (USHORT)OldLength;
909 
910         RtlAppendUnicodeStringToString(&NameU, &RawSuffix);
911 
912         Status = ZwSetValueKey(PnpMgrLevel2,
913                                &NameU,
914                                0,
915                                REG_RESOURCE_LIST,
916                                DeviceNode->ResourceList,
917                                PnpDetermineResourceListSize(DeviceNode->ResourceList));
918         if (!NT_SUCCESS(Status))
919         {
920             ZwClose(PnpMgrLevel2);
921             ExFreePool(NameU.Buffer);
922             return Status;
923         }
924 
925         /* "Remove" the suffix by setting the length back to what it used to be */
926         NameU.Length = (USHORT)OldLength;
927 
928         RtlAppendUnicodeStringToString(&NameU, &TranslatedSuffix);
929 
930         Status = ZwSetValueKey(PnpMgrLevel2,
931                                &NameU,
932                                0,
933                                REG_RESOURCE_LIST,
934                                DeviceNode->ResourceListTranslated,
935                                PnpDetermineResourceListSize(DeviceNode->ResourceListTranslated));
936         ZwClose(PnpMgrLevel2);
937         ExFreePool(NameU.Buffer);
938 
939         if (!NT_SUCCESS(Status))
940             return Status;
941     }
942     else
943     {
944         ZwClose(PnpMgrLevel2);
945     }
946 
947     return STATUS_SUCCESS;
948 }
949 
950 NTSTATUS
951 IopUpdateResourceMapForPnPDevice(
952     IN PDEVICE_NODE DeviceNode)
953 {
954     return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager");
955 }
956 
957 static
958 NTSTATUS
959 IopTranslateDeviceResources(
960    IN PDEVICE_NODE DeviceNode)
961 {
962    PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
963    PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
964    PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
965    ULONG i, j, ListSize;
966    NTSTATUS Status;
967 
968    if (!DeviceNode->ResourceList)
969    {
970       DeviceNode->ResourceListTranslated = NULL;
971       return STATUS_SUCCESS;
972    }
973 
974    /* That's easy to translate a resource list. Just copy the
975     * untranslated one and change few fields in the copy
976     */
977    ListSize = PnpDetermineResourceListSize(DeviceNode->ResourceList);
978 
979    DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, ListSize);
980    if (!DeviceNode->ResourceListTranslated)
981    {
982       Status = STATUS_NO_MEMORY;
983       goto cleanup;
984    }
985    RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, ListSize);
986 
987    FullDescriptor = &DeviceNode->ResourceList->List[0];
988    for (i = 0; i < DeviceNode->ResourceList->Count; i++)
989    {
990       pPartialResourceList = &FullDescriptor->PartialResourceList;
991       FullDescriptor = CmiGetNextResourceDescriptor(FullDescriptor);
992 
993       for (j = 0; j < pPartialResourceList->Count; j++)
994       {
995         /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific),
996            but only one is allowed and it must be the last one in the list! */
997          DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
998 
999          /* Calculate the location of the translated resource descriptor */
1000          DescriptorTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)(
1001              (PUCHAR)DeviceNode->ResourceListTranslated +
1002              ((PUCHAR)DescriptorRaw - (PUCHAR)DeviceNode->ResourceList));
1003 
1004          switch (DescriptorRaw->Type)
1005          {
1006             case CmResourceTypePort:
1007             {
1008                ULONG AddressSpace = 1; /* IO space */
1009                if (!HalTranslateBusAddress(
1010                   DeviceNode->ResourceList->List[i].InterfaceType,
1011                   DeviceNode->ResourceList->List[i].BusNumber,
1012                   DescriptorRaw->u.Port.Start,
1013                   &AddressSpace,
1014                   &DescriptorTranslated->u.Port.Start))
1015                {
1016                   Status = STATUS_UNSUCCESSFUL;
1017                   DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw->u.Port.Start.QuadPart);
1018                   goto cleanup;
1019                }
1020 
1021                if (AddressSpace == 0)
1022                {
1023                    DPRINT1("Guessed incorrect address space: 1 -> 0\n");
1024 
1025                    /* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are
1026                     * invalid for this state but I'm not 100% sure */
1027                    DescriptorRaw->Flags =
1028                    DescriptorTranslated->Flags = CM_RESOURCE_PORT_MEMORY;
1029                }
1030                break;
1031             }
1032             case CmResourceTypeInterrupt:
1033             {
1034                KIRQL Irql;
1035                DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
1036                   DeviceNode->ResourceList->List[i].InterfaceType,
1037                   DeviceNode->ResourceList->List[i].BusNumber,
1038                   DescriptorRaw->u.Interrupt.Level,
1039                   DescriptorRaw->u.Interrupt.Vector,
1040                   &Irql,
1041                   &DescriptorTranslated->u.Interrupt.Affinity);
1042                DescriptorTranslated->u.Interrupt.Level = Irql;
1043                if (!DescriptorTranslated->u.Interrupt.Vector)
1044                {
1045                    Status = STATUS_UNSUCCESSFUL;
1046                    DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw->u.Interrupt.Vector,
1047                                                                                                    DescriptorRaw->u.Interrupt.Level);
1048                    goto cleanup;
1049                }
1050                break;
1051             }
1052             case CmResourceTypeMemory:
1053             {
1054                ULONG AddressSpace = 0; /* Memory space */
1055                if (!HalTranslateBusAddress(
1056                   DeviceNode->ResourceList->List[i].InterfaceType,
1057                   DeviceNode->ResourceList->List[i].BusNumber,
1058                   DescriptorRaw->u.Memory.Start,
1059                   &AddressSpace,
1060                   &DescriptorTranslated->u.Memory.Start))
1061                {
1062                   Status = STATUS_UNSUCCESSFUL;
1063                   DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw->u.Memory.Start.QuadPart);
1064                   goto cleanup;
1065                }
1066 
1067                if (AddressSpace != 0)
1068                {
1069                    DPRINT1("Guessed incorrect address space: 0 -> 1\n");
1070 
1071                    /* This should never happen for memory space */
1072                    ASSERT(FALSE);
1073                }
1074             }
1075 
1076             case CmResourceTypeDma:
1077             case CmResourceTypeBusNumber:
1078             case CmResourceTypeDeviceSpecific:
1079                /* Nothing to do */
1080                break;
1081             default:
1082                DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
1083                Status = STATUS_NOT_IMPLEMENTED;
1084                goto cleanup;
1085          }
1086       }
1087    }
1088    return STATUS_SUCCESS;
1089 
1090 cleanup:
1091    /* Yes! Also delete ResourceList because ResourceList and
1092     * ResourceListTranslated should be a pair! */
1093    ExFreePool(DeviceNode->ResourceList);
1094    DeviceNode->ResourceList = NULL;
1095    if (DeviceNode->ResourceListTranslated)
1096    {
1097       ExFreePool(DeviceNode->ResourceListTranslated);
1098       DeviceNode->ResourceList = NULL;
1099    }
1100    return Status;
1101 }
1102 
1103 NTSTATUS
1104 NTAPI
1105 IopAssignDeviceResources(
1106    IN PDEVICE_NODE DeviceNode)
1107 {
1108    NTSTATUS Status;
1109    ULONG ListSize;
1110 
1111    IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
1112 
1113    Status = IopFilterResourceRequirements(DeviceNode);
1114    if (!NT_SUCCESS(Status))
1115        goto ByeBye;
1116 
1117    if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
1118    {
1119       DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
1120       DeviceNode->Flags &= ~DNF_ASSIGNING_RESOURCES;
1121 
1122       /* No resource needed for this device */
1123       DeviceNode->ResourceList = NULL;
1124       DeviceNode->ResourceListTranslated = NULL;
1125 
1126       return STATUS_SUCCESS;
1127    }
1128 
1129    if (DeviceNode->BootResources)
1130    {
1131        ListSize = PnpDetermineResourceListSize(DeviceNode->BootResources);
1132 
1133        DeviceNode->ResourceList = ExAllocatePool(PagedPool, ListSize);
1134        if (!DeviceNode->ResourceList)
1135        {
1136            Status = STATUS_NO_MEMORY;
1137            goto ByeBye;
1138        }
1139 
1140        RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, ListSize);
1141 
1142        Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
1143        if (!NT_SUCCESS(Status))
1144        {
1145            DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
1146            ExFreePool(DeviceNode->ResourceList);
1147            DeviceNode->ResourceList = NULL;
1148        }
1149    }
1150    else
1151    {
1152        /* We'll make this from the requirements */
1153        DeviceNode->ResourceList = NULL;
1154    }
1155 
1156    /* No resources requirements */
1157    if (!DeviceNode->ResourceRequirements)
1158        goto Finish;
1159 
1160    /* Call HAL to fixup our resource requirements list */
1161    HalAdjustResourceList(&DeviceNode->ResourceRequirements);
1162 
1163    /* Add resource requirements that aren't in the list we already got */
1164    Status = IopFixupResourceListWithRequirements(DeviceNode->ResourceRequirements,
1165                                                  &DeviceNode->ResourceList);
1166    if (!NT_SUCCESS(Status))
1167    {
1168        DPRINT1("Failed to fixup a resource list from supplied resources for %wZ\n", &DeviceNode->InstancePath);
1169        DeviceNode->Problem = CM_PROB_NORMAL_CONFLICT;
1170        goto ByeBye;
1171    }
1172 
1173    /* IopFixupResourceListWithRequirements should NEVER give us a conflicting list */
1174    ASSERT(IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL) != STATUS_CONFLICTING_ADDRESSES);
1175 
1176 Finish:
1177    Status = IopTranslateDeviceResources(DeviceNode);
1178    if (!NT_SUCCESS(Status))
1179    {
1180        DeviceNode->Problem = CM_PROB_TRANSLATION_FAILED;
1181        DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode->InstancePath);
1182        goto ByeBye;
1183    }
1184 
1185    Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
1186    if (!NT_SUCCESS(Status))
1187        goto ByeBye;
1188 
1189    Status = IopUpdateControlKeyWithResources(DeviceNode);
1190    if (!NT_SUCCESS(Status))
1191        goto ByeBye;
1192 
1193    IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
1194 
1195    IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
1196 
1197    return STATUS_SUCCESS;
1198 
1199 ByeBye:
1200    if (DeviceNode->ResourceList)
1201    {
1202       ExFreePool(DeviceNode->ResourceList);
1203       DeviceNode->ResourceList = NULL;
1204    }
1205 
1206    DeviceNode->ResourceListTranslated = NULL;
1207 
1208    IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
1209 
1210    return Status;
1211 }
1212 
1213 static
1214 BOOLEAN
1215 IopCheckForResourceConflict(
1216    IN PCM_RESOURCE_LIST ResourceList1,
1217    IN PCM_RESOURCE_LIST ResourceList2,
1218    IN BOOLEAN Silent,
1219    OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1220 {
1221    ULONG i, ii;
1222    BOOLEAN Result = FALSE;
1223    PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor;
1224 
1225    FullDescriptor = &ResourceList1->List[0];
1226    for (i = 0; i < ResourceList1->Count; i++)
1227    {
1228       PCM_PARTIAL_RESOURCE_LIST ResList = &FullDescriptor->PartialResourceList;
1229       FullDescriptor = CmiGetNextResourceDescriptor(FullDescriptor);
1230 
1231       for (ii = 0; ii < ResList->Count; ii++)
1232       {
1233         /* Partial resource descriptors can be of variable size (CmResourceTypeDeviceSpecific),
1234            but only one is allowed and it must be the last one in the list! */
1235          PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
1236 
1237          Result = IopCheckResourceDescriptor(ResDesc,
1238                                              ResourceList2,
1239                                              Silent,
1240                                              ConflictingDescriptor);
1241          if (Result) goto ByeBye;
1242       }
1243    }
1244 
1245 ByeBye:
1246 
1247    return Result;
1248 }
1249 
1250 NTSTATUS NTAPI
1251 IopDetectResourceConflict(
1252    IN PCM_RESOURCE_LIST ResourceList,
1253    IN BOOLEAN Silent,
1254    OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1255 {
1256    OBJECT_ATTRIBUTES ObjectAttributes;
1257    UNICODE_STRING KeyName;
1258    HANDLE ResourceMapKey = NULL, ChildKey2 = NULL, ChildKey3 = NULL;
1259    ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
1260    PKEY_BASIC_INFORMATION KeyInformation;
1261    PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
1262    PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
1263    ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0;
1264    NTSTATUS Status;
1265 
1266    RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1267    InitializeObjectAttributes(&ObjectAttributes,
1268                               &KeyName,
1269                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1270                               NULL,
1271                               NULL);
1272    Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1273    if (!NT_SUCCESS(Status))
1274    {
1275       /* The key is missing which means we are the first device */
1276       return STATUS_SUCCESS;
1277    }
1278 
1279    while (TRUE)
1280    {
1281       Status = ZwEnumerateKey(ResourceMapKey,
1282                               ChildKeyIndex1,
1283                               KeyBasicInformation,
1284                               NULL,
1285                               0,
1286                               &RequiredLength);
1287       if (Status == STATUS_NO_MORE_ENTRIES)
1288           break;
1289       else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1290       {
1291           KeyInformationLength = RequiredLength;
1292           KeyInformation = ExAllocatePoolWithTag(PagedPool,
1293                                                  KeyInformationLength,
1294                                                  TAG_IO);
1295           if (!KeyInformation)
1296           {
1297               Status = STATUS_INSUFFICIENT_RESOURCES;
1298               goto cleanup;
1299           }
1300 
1301           Status = ZwEnumerateKey(ResourceMapKey,
1302                                   ChildKeyIndex1,
1303                                   KeyBasicInformation,
1304                                   KeyInformation,
1305                                   KeyInformationLength,
1306                                   &RequiredLength);
1307       }
1308       else
1309          goto cleanup;
1310       ChildKeyIndex1++;
1311       if (!NT_SUCCESS(Status))
1312       {
1313           ExFreePoolWithTag(KeyInformation, TAG_IO);
1314           goto cleanup;
1315       }
1316 
1317       KeyName.Buffer = KeyInformation->Name;
1318       KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
1319       InitializeObjectAttributes(&ObjectAttributes,
1320                                  &KeyName,
1321                                  OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1322                                  ResourceMapKey,
1323                                  NULL);
1324       Status = ZwOpenKey(&ChildKey2,
1325                          KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
1326                          &ObjectAttributes);
1327       ExFreePoolWithTag(KeyInformation, TAG_IO);
1328       if (!NT_SUCCESS(Status))
1329           goto cleanup;
1330 
1331       while (TRUE)
1332       {
1333           Status = ZwEnumerateKey(ChildKey2,
1334                                   ChildKeyIndex2,
1335                                   KeyBasicInformation,
1336                                   NULL,
1337                                   0,
1338                                   &RequiredLength);
1339           if (Status == STATUS_NO_MORE_ENTRIES)
1340               break;
1341           else if (Status == STATUS_BUFFER_TOO_SMALL)
1342           {
1343               KeyInformationLength = RequiredLength;
1344               KeyInformation = ExAllocatePoolWithTag(PagedPool,
1345                                                      KeyInformationLength,
1346                                                      TAG_IO);
1347               if (!KeyInformation)
1348               {
1349                   Status = STATUS_INSUFFICIENT_RESOURCES;
1350                   goto cleanup;
1351               }
1352 
1353               Status = ZwEnumerateKey(ChildKey2,
1354                                       ChildKeyIndex2,
1355                                       KeyBasicInformation,
1356                                       KeyInformation,
1357                                       KeyInformationLength,
1358                                       &RequiredLength);
1359           }
1360           else
1361               goto cleanup;
1362           ChildKeyIndex2++;
1363           if (!NT_SUCCESS(Status))
1364           {
1365               ExFreePoolWithTag(KeyInformation, TAG_IO);
1366               goto cleanup;
1367           }
1368 
1369           KeyName.Buffer = KeyInformation->Name;
1370           KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
1371           InitializeObjectAttributes(&ObjectAttributes,
1372                                      &KeyName,
1373                                      OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1374                                      ChildKey2,
1375                                      NULL);
1376           Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
1377           ExFreePoolWithTag(KeyInformation, TAG_IO);
1378           if (!NT_SUCCESS(Status))
1379               goto cleanup;
1380 
1381           while (TRUE)
1382           {
1383               Status = ZwEnumerateValueKey(ChildKey3,
1384                                            ChildKeyIndex3,
1385                                            KeyValuePartialInformation,
1386                                            NULL,
1387                                            0,
1388                                            &RequiredLength);
1389               if (Status == STATUS_NO_MORE_ENTRIES)
1390                   break;
1391               else if (Status == STATUS_BUFFER_TOO_SMALL)
1392               {
1393                   KeyValueInformationLength = RequiredLength;
1394                   KeyValueInformation = ExAllocatePoolWithTag(PagedPool,
1395                                                               KeyValueInformationLength,
1396                                                               TAG_IO);
1397                   if (!KeyValueInformation)
1398                   {
1399                       Status = STATUS_INSUFFICIENT_RESOURCES;
1400                       goto cleanup;
1401                   }
1402 
1403                   Status = ZwEnumerateValueKey(ChildKey3,
1404                                                ChildKeyIndex3,
1405                                                KeyValuePartialInformation,
1406                                                KeyValueInformation,
1407                                                KeyValueInformationLength,
1408                                                &RequiredLength);
1409               }
1410               else
1411                   goto cleanup;
1412               if (!NT_SUCCESS(Status))
1413               {
1414                   ExFreePoolWithTag(KeyValueInformation, TAG_IO);
1415                   goto cleanup;
1416               }
1417 
1418               Status = ZwEnumerateValueKey(ChildKey3,
1419                                            ChildKeyIndex3,
1420                                            KeyValueBasicInformation,
1421                                            NULL,
1422                                            0,
1423                                            &RequiredLength);
1424               if (Status == STATUS_BUFFER_TOO_SMALL)
1425               {
1426                   KeyNameInformationLength = RequiredLength;
1427                   KeyNameInformation = ExAllocatePoolWithTag(PagedPool,
1428                                                              KeyNameInformationLength + sizeof(WCHAR),
1429                                                              TAG_IO);
1430                   if (!KeyNameInformation)
1431                   {
1432                       Status = STATUS_INSUFFICIENT_RESOURCES;
1433                       goto cleanup;
1434                   }
1435 
1436                   Status = ZwEnumerateValueKey(ChildKey3,
1437                                                ChildKeyIndex3,
1438                                                KeyValueBasicInformation,
1439                                                KeyNameInformation,
1440                                                KeyNameInformationLength,
1441                                                &RequiredLength);
1442               }
1443               else
1444                   goto cleanup;
1445               ChildKeyIndex3++;
1446               if (!NT_SUCCESS(Status))
1447               {
1448                   ExFreePoolWithTag(KeyNameInformation, TAG_IO);
1449                   goto cleanup;
1450               }
1451 
1452               KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
1453 
1454               /* Skip translated entries */
1455               if (wcsstr(KeyNameInformation->Name, L".Translated"))
1456               {
1457                   ExFreePoolWithTag(KeyNameInformation, TAG_IO);
1458                   ExFreePoolWithTag(KeyValueInformation, TAG_IO);
1459                   continue;
1460               }
1461 
1462               ExFreePoolWithTag(KeyNameInformation, TAG_IO);
1463 
1464               if (IopCheckForResourceConflict(ResourceList,
1465                                               (PCM_RESOURCE_LIST)KeyValueInformation->Data,
1466                                               Silent,
1467                                               ConflictingDescriptor))
1468               {
1469                   ExFreePoolWithTag(KeyValueInformation, TAG_IO);
1470                   Status = STATUS_CONFLICTING_ADDRESSES;
1471                   goto cleanup;
1472               }
1473 
1474               ExFreePoolWithTag(KeyValueInformation, TAG_IO);
1475           }
1476       }
1477    }
1478 
1479 cleanup:
1480    if (ResourceMapKey != NULL)
1481        ObCloseHandle(ResourceMapKey, KernelMode);
1482    if (ChildKey2 != NULL)
1483        ObCloseHandle(ChildKey2, KernelMode);
1484    if (ChildKey3 != NULL)
1485        ObCloseHandle(ChildKey3, KernelMode);
1486 
1487    if (Status == STATUS_NO_MORE_ENTRIES)
1488        Status = STATUS_SUCCESS;
1489 
1490    return Status;
1491 }
1492 
1493