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