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