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