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