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