xref: /reactos/ntoskrnl/io/pnpmgr/pnpres.c (revision c2d0d784)
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;
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             return TRUE;
63         }
64    }
65 
66    return FALSE;
67 }
68 
69 static
70 BOOLEAN
71 IopFindMemoryResource(
72    IN PIO_RESOURCE_DESCRIPTOR IoDesc,
73    OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
74 {
75    LONGLONG Start;
76    CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
77 
78    ASSERT(IoDesc->Type == CmDesc->Type);
79    ASSERT(IoDesc->Type == CmResourceTypeMemory);
80 
81    /* HACK */
82    if (IoDesc->u.Memory.Alignment == 0) IoDesc->u.Memory.Alignment = 1;
83 
84    for (Start = IoDesc->u.Memory.MinimumAddress.QuadPart;
85         Start <= IoDesc->u.Memory.MaximumAddress.QuadPart;
86         Start += IoDesc->u.Memory.Alignment)
87    {
88         CmDesc->u.Memory.Length = IoDesc->u.Memory.Length;
89         CmDesc->u.Memory.Start.QuadPart = Start;
90 
91         if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
92         {
93             Start += ConflictingDesc.u.Memory.Start.QuadPart +
94                      ConflictingDesc.u.Memory.Length;
95         }
96         else
97         {
98             return TRUE;
99         }
100    }
101 
102    return FALSE;
103 }
104 
105 static
106 BOOLEAN
107 IopFindPortResource(
108    IN PIO_RESOURCE_DESCRIPTOR IoDesc,
109    OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
110 {
111    LONGLONG Start;
112    CM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDesc;
113 
114    ASSERT(IoDesc->Type == CmDesc->Type);
115    ASSERT(IoDesc->Type == CmResourceTypePort);
116 
117    /* HACK */
118    if (IoDesc->u.Port.Alignment == 0) IoDesc->u.Port.Alignment = 1;
119 
120    for (Start = IoDesc->u.Port.MinimumAddress.QuadPart;
121         Start <= IoDesc->u.Port.MaximumAddress.QuadPart;
122         Start += IoDesc->u.Port.Alignment)
123    {
124         CmDesc->u.Port.Length = IoDesc->u.Port.Length;
125         CmDesc->u.Port.Start.QuadPart = Start;
126 
127         if (IopCheckDescriptorForConflict(CmDesc, &ConflictingDesc))
128         {
129             Start += ConflictingDesc.u.Port.Start.QuadPart + ConflictingDesc.u.Port.Length;
130         }
131         else
132         {
133             return TRUE;
134         }
135    }
136 
137    return FALSE;
138 }
139 
140 static
141 BOOLEAN
142 IopFindDmaResource(
143    IN PIO_RESOURCE_DESCRIPTOR IoDesc,
144    OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
145 {
146    ULONG Channel;
147 
148    ASSERT(IoDesc->Type == CmDesc->Type);
149    ASSERT(IoDesc->Type == CmResourceTypeDma);
150 
151    for (Channel = IoDesc->u.Dma.MinimumChannel;
152         Channel <= IoDesc->u.Dma.MaximumChannel;
153         Channel++)
154    {
155         CmDesc->u.Dma.Channel = Channel;
156         CmDesc->u.Dma.Port = 0;
157 
158         if (!IopCheckDescriptorForConflict(CmDesc, NULL))
159             return TRUE;
160    }
161 
162    return FALSE;
163 }
164 
165 static
166 BOOLEAN
167 IopFindInterruptResource(
168    IN PIO_RESOURCE_DESCRIPTOR IoDesc,
169    OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc)
170 {
171    ULONG Vector;
172 
173    ASSERT(IoDesc->Type == CmDesc->Type);
174    ASSERT(IoDesc->Type == CmResourceTypeInterrupt);
175 
176    for (Vector = IoDesc->u.Interrupt.MinimumVector;
177         Vector <= IoDesc->u.Interrupt.MaximumVector;
178         Vector++)
179    {
180         CmDesc->u.Interrupt.Vector = Vector;
181         CmDesc->u.Interrupt.Level = Vector;
182         CmDesc->u.Interrupt.Affinity = (KAFFINITY)-1;
183 
184         if (!IopCheckDescriptorForConflict(CmDesc, NULL))
185             return TRUE;
186    }
187 
188    return FALSE;
189 }
190 
191 
192 NTSTATUS NTAPI
193 IopCreateResourceListFromRequirements(
194    IN PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList,
195    OUT PCM_RESOURCE_LIST *ResourceList)
196 {
197    ULONG i, ii, Size;
198    PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc;
199 
200    Size = FIELD_OFFSET(CM_RESOURCE_LIST, List);
201    for (i = 0; i < RequirementsList->AlternativeLists; i++)
202    {
203       PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
204       Size += FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
205         + ResList->Count * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
206    }
207 
208    *ResourceList = ExAllocatePool(PagedPool, Size);
209    if (!*ResourceList)
210        return STATUS_INSUFFICIENT_RESOURCES;
211 
212    (*ResourceList)->Count = 1;
213    (*ResourceList)->List[0].BusNumber = RequirementsList->BusNumber;
214    (*ResourceList)->List[0].InterfaceType = RequirementsList->InterfaceType;
215    (*ResourceList)->List[0].PartialResourceList.Version = 1;
216    (*ResourceList)->List[0].PartialResourceList.Revision = 1;
217    (*ResourceList)->List[0].PartialResourceList.Count = 0;
218 
219    ResDesc = &(*ResourceList)->List[0].PartialResourceList.PartialDescriptors[0];
220 
221    for (i = 0; i < RequirementsList->AlternativeLists; i++)
222    {
223       PIO_RESOURCE_LIST ResList = &RequirementsList->List[i];
224       for (ii = 0; ii < ResList->Count; ii++)
225       {
226          PIO_RESOURCE_DESCRIPTOR ReqDesc = &ResList->Descriptors[ii];
227          BOOLEAN FoundResource = TRUE;
228 
229          /* FIXME: Handle alternate ranges */
230          if (ReqDesc->Option == IO_RESOURCE_ALTERNATIVE)
231              continue;
232 
233          ResDesc->Type = ReqDesc->Type;
234          ResDesc->Flags = ReqDesc->Flags;
235          ResDesc->ShareDisposition = ReqDesc->ShareDisposition;
236 
237          switch (ReqDesc->Type)
238          {
239             case CmResourceTypeInterrupt:
240               if (!IopFindInterruptResource(ReqDesc, ResDesc))
241               {
242                   DPRINT1("Failed to find an available interrupt resource (0x%x to 0x%x)\n",
243                            ReqDesc->u.Interrupt.MinimumVector, ReqDesc->u.Interrupt.MaximumVector);
244 
245                   if (ReqDesc->Option == 0)
246                   {
247                       ExFreePool(*ResourceList);
248                       *ResourceList = NULL;
249                       return STATUS_CONFLICTING_ADDRESSES;
250                   }
251 
252                   FoundResource = FALSE;
253               }
254               break;
255 
256             case CmResourceTypePort:
257               if (!IopFindPortResource(ReqDesc, ResDesc))
258               {
259                   DPRINT1("Failed to find an available port resource (0x%I64x to 0x%I64x length: 0x%x)\n",
260                           ReqDesc->u.Port.MinimumAddress.QuadPart, ReqDesc->u.Port.MaximumAddress.QuadPart,
261                           ReqDesc->u.Port.Length);
262 
263                   if (ReqDesc->Option == 0)
264                   {
265                       ExFreePool(*ResourceList);
266                       *ResourceList = NULL;
267                       return STATUS_CONFLICTING_ADDRESSES;
268                   }
269 
270                   FoundResource = FALSE;
271               }
272               break;
273 
274             case CmResourceTypeMemory:
275               if (!IopFindMemoryResource(ReqDesc, ResDesc))
276               {
277                   DPRINT1("Failed to find an available memory resource (0x%I64x to 0x%I64x length: 0x%x)\n",
278                           ReqDesc->u.Memory.MinimumAddress.QuadPart, ReqDesc->u.Memory.MaximumAddress.QuadPart,
279                           ReqDesc->u.Memory.Length);
280 
281                   if (ReqDesc->Option == 0)
282                   {
283                       ExFreePool(*ResourceList);
284                       *ResourceList = NULL;
285                       return STATUS_CONFLICTING_ADDRESSES;
286                   }
287 
288                   FoundResource = FALSE;
289               }
290               break;
291 
292             case CmResourceTypeBusNumber:
293               if (!IopFindBusNumberResource(ReqDesc, ResDesc))
294               {
295                   DPRINT1("Failed to find an available bus number resource (0x%x to 0x%x length: 0x%x)\n",
296                           ReqDesc->u.BusNumber.MinBusNumber, ReqDesc->u.BusNumber.MaxBusNumber,
297                           ReqDesc->u.BusNumber.Length);
298 
299                   if (ReqDesc->Option == 0)
300                   {
301                       ExFreePool(*ResourceList);
302                       *ResourceList = NULL;
303                       return STATUS_CONFLICTING_ADDRESSES;
304                   }
305 
306                   FoundResource = FALSE;
307               }
308               break;
309 
310             case CmResourceTypeDma:
311               if (!IopFindDmaResource(ReqDesc, ResDesc))
312               {
313                   DPRINT1("Failed to find an available dma resource (0x%x to 0x%x)\n",
314                           ReqDesc->u.Dma.MinimumChannel, ReqDesc->u.Dma.MaximumChannel);
315 
316                   if (ReqDesc->Option == 0)
317                   {
318                       ExFreePool(*ResourceList);
319                       *ResourceList = NULL;
320                       return STATUS_CONFLICTING_ADDRESSES;
321                   }
322 
323                   FoundResource = FALSE;
324               }
325               break;
326 
327             default:
328               DPRINT1("Unsupported resource type: %x\n", ReqDesc->Type);
329               FoundResource = FALSE;
330               break;
331          }
332 
333          if (FoundResource)
334          {
335              (*ResourceList)->List[0].PartialResourceList.Count++;
336              ResDesc++;
337          }
338       }
339    }
340 
341    return STATUS_SUCCESS;
342 }
343 
344 static
345 BOOLEAN
346 IopCheckResourceDescriptor(
347    IN PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc,
348    IN PCM_RESOURCE_LIST ResourceList,
349    IN BOOLEAN Silent,
350    OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
351 {
352    ULONG i, ii;
353    BOOLEAN Result = FALSE;
354 
355    for (i = 0; i < ResourceList->Count; i++)
356    {
357       PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList->List[i].PartialResourceList;
358       for (ii = 0; ii < ResList->Count; ii++)
359       {
360          PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc2 = &ResList->PartialDescriptors[ii];
361 
362          /* We don't care about shared resources */
363          if (ResDesc->ShareDisposition == CmResourceShareShared &&
364              ResDesc2->ShareDisposition == CmResourceShareShared)
365              continue;
366 
367          /* Make sure we're comparing the same types */
368          if (ResDesc->Type != ResDesc2->Type)
369              continue;
370 
371          switch (ResDesc->Type)
372          {
373              case CmResourceTypeMemory:
374                  if ((ResDesc->u.Memory.Start.QuadPart < ResDesc2->u.Memory.Start.QuadPart &&
375                       ResDesc->u.Memory.Start.QuadPart + ResDesc->u.Memory.Length >
376                       ResDesc2->u.Memory.Start.QuadPart) || (ResDesc2->u.Memory.Start.QuadPart <
377                       ResDesc->u.Memory.Start.QuadPart && ResDesc2->u.Memory.Start.QuadPart +
378                       ResDesc2->u.Memory.Length > ResDesc->u.Memory.Start.QuadPart))
379                  {
380                       if (!Silent)
381                       {
382                           DPRINT1("Resource conflict: Memory (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
383                                   ResDesc->u.Memory.Start.QuadPart, ResDesc->u.Memory.Start.QuadPart +
384                                   ResDesc->u.Memory.Length, ResDesc2->u.Memory.Start.QuadPart,
385                                   ResDesc2->u.Memory.Start.QuadPart + ResDesc2->u.Memory.Length);
386                       }
387 
388                       Result = TRUE;
389 
390                       goto ByeBye;
391                  }
392                  break;
393 
394              case CmResourceTypePort:
395                  if ((ResDesc->u.Port.Start.QuadPart < ResDesc2->u.Port.Start.QuadPart &&
396                       ResDesc->u.Port.Start.QuadPart + ResDesc->u.Port.Length >
397                       ResDesc2->u.Port.Start.QuadPart) || (ResDesc2->u.Port.Start.QuadPart <
398                       ResDesc->u.Port.Start.QuadPart && ResDesc2->u.Port.Start.QuadPart +
399                       ResDesc2->u.Port.Length > ResDesc->u.Port.Start.QuadPart))
400                  {
401                       if (!Silent)
402                       {
403                           DPRINT1("Resource conflict: Port (0x%I64x to 0x%I64x vs. 0x%I64x to 0x%I64x)\n",
404                                   ResDesc->u.Port.Start.QuadPart, ResDesc->u.Port.Start.QuadPart +
405                                   ResDesc->u.Port.Length, ResDesc2->u.Port.Start.QuadPart,
406                                   ResDesc2->u.Port.Start.QuadPart + ResDesc2->u.Port.Length);
407                       }
408 
409                       Result = TRUE;
410 
411                       goto ByeBye;
412                  }
413                  break;
414 
415              case CmResourceTypeInterrupt:
416                  if (ResDesc->u.Interrupt.Vector == ResDesc2->u.Interrupt.Vector)
417                  {
418                       if (!Silent)
419                       {
420                           DPRINT1("Resource conflict: IRQ (0x%x 0x%x vs. 0x%x 0x%x)\n",
421                                   ResDesc->u.Interrupt.Vector, ResDesc->u.Interrupt.Level,
422                                   ResDesc2->u.Interrupt.Vector, ResDesc2->u.Interrupt.Level);
423                       }
424 
425                       Result = TRUE;
426 
427                       goto ByeBye;
428                  }
429                  break;
430 
431              case CmResourceTypeBusNumber:
432                  if ((ResDesc->u.BusNumber.Start < ResDesc2->u.BusNumber.Start &&
433                       ResDesc->u.BusNumber.Start + ResDesc->u.BusNumber.Length >
434                       ResDesc2->u.BusNumber.Start) || (ResDesc2->u.BusNumber.Start <
435                       ResDesc->u.BusNumber.Start && ResDesc2->u.BusNumber.Start +
436                       ResDesc2->u.BusNumber.Length > ResDesc->u.BusNumber.Start))
437                  {
438                       if (!Silent)
439                       {
440                           DPRINT1("Resource conflict: Bus number (0x%x to 0x%x vs. 0x%x to 0x%x)\n",
441                                   ResDesc->u.BusNumber.Start, ResDesc->u.BusNumber.Start +
442                                   ResDesc->u.BusNumber.Length, ResDesc2->u.BusNumber.Start,
443                                   ResDesc2->u.BusNumber.Start + ResDesc2->u.BusNumber.Length);
444                       }
445 
446                       Result = TRUE;
447 
448                       goto ByeBye;
449                  }
450                  break;
451 
452              case CmResourceTypeDma:
453                  if (ResDesc->u.Dma.Channel == ResDesc2->u.Dma.Channel)
454                  {
455                      if (!Silent)
456                      {
457                          DPRINT1("Resource conflict: Dma (0x%x 0x%x vs. 0x%x 0x%x)\n",
458                                  ResDesc->u.Dma.Channel, ResDesc->u.Dma.Port,
459                                  ResDesc2->u.Dma.Channel, ResDesc2->u.Dma.Port);
460                      }
461 
462                      Result = TRUE;
463 
464                      goto ByeBye;
465                  }
466                  break;
467          }
468       }
469    }
470 
471 ByeBye:
472 
473    if (Result && ConflictingDescriptor)
474    {
475        RtlCopyMemory(ConflictingDescriptor,
476                      ResDesc,
477                      sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
478    }
479 
480    return Result;
481 }
482 
483 static
484 NTSTATUS
485 IopUpdateControlKeyWithResources(IN PDEVICE_NODE DeviceNode)
486 {
487    UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
488    UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control");
489    UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"AllocConfig");
490    HANDLE EnumKey, InstanceKey, ControlKey;
491    NTSTATUS Status;
492    OBJECT_ATTRIBUTES ObjectAttributes;
493 
494    /* Open the Enum key */
495    Status = IopOpenRegistryKeyEx(&EnumKey, NULL, &EnumRoot, KEY_ENUMERATE_SUB_KEYS);
496    if (!NT_SUCCESS(Status))
497        return Status;
498 
499    /* Open the instance key (eg. Root\PNP0A03) */
500    Status = IopOpenRegistryKeyEx(&InstanceKey, EnumKey, &DeviceNode->InstancePath, KEY_ENUMERATE_SUB_KEYS);
501    ZwClose(EnumKey);
502 
503    if (!NT_SUCCESS(Status))
504        return Status;
505 
506    /* Create/Open the Control key */
507    InitializeObjectAttributes(&ObjectAttributes,
508                               &Control,
509                               OBJ_CASE_INSENSITIVE,
510                               InstanceKey,
511                               NULL);
512    Status = ZwCreateKey(&ControlKey,
513                         KEY_SET_VALUE,
514                         &ObjectAttributes,
515                         0,
516                         NULL,
517                         REG_OPTION_VOLATILE,
518                         NULL);
519    ZwClose(InstanceKey);
520 
521    if (!NT_SUCCESS(Status))
522        return Status;
523 
524    /* Write the resource list */
525    Status = ZwSetValueKey(ControlKey,
526                           &ValueName,
527                           0,
528                           REG_RESOURCE_LIST,
529                           DeviceNode->ResourceList,
530                           PnpDetermineResourceListSize(DeviceNode->ResourceList));
531    ZwClose(ControlKey);
532 
533    if (!NT_SUCCESS(Status))
534        return Status;
535 
536    return STATUS_SUCCESS;
537 }
538 
539 static
540 NTSTATUS
541 IopFilterResourceRequirements(IN PDEVICE_NODE DeviceNode)
542 {
543    IO_STACK_LOCATION Stack;
544    IO_STATUS_BLOCK IoStatusBlock;
545    NTSTATUS Status;
546 
547    DPRINT("Sending IRP_MN_FILTER_RESOURCE_REQUIREMENTS to device stack\n");
548 
549    Stack.Parameters.FilterResourceRequirements.IoResourceRequirementList = DeviceNode->ResourceRequirements;
550    Status = IopInitiatePnpIrp(
551       DeviceNode->PhysicalDeviceObject,
552       &IoStatusBlock,
553       IRP_MN_FILTER_RESOURCE_REQUIREMENTS,
554       &Stack);
555    if (!NT_SUCCESS(Status) && Status != STATUS_NOT_SUPPORTED)
556    {
557       DPRINT1("IopInitiatePnpIrp(IRP_MN_FILTER_RESOURCE_REQUIREMENTS) failed\n");
558       return Status;
559    }
560    else if (NT_SUCCESS(Status) && IoStatusBlock.Information)
561    {
562       DeviceNode->ResourceRequirements = (PIO_RESOURCE_REQUIREMENTS_LIST)IoStatusBlock.Information;
563    }
564 
565    return STATUS_SUCCESS;
566 }
567 
568 
569 NTSTATUS
570 IopUpdateResourceMap(IN PDEVICE_NODE DeviceNode, PWCHAR Level1Key, PWCHAR Level2Key)
571 {
572   NTSTATUS Status;
573   ULONG Disposition;
574   HANDLE PnpMgrLevel1, PnpMgrLevel2, ResourceMapKey;
575   UNICODE_STRING KeyName;
576   OBJECT_ATTRIBUTES ObjectAttributes;
577 
578   RtlInitUnicodeString(&KeyName,
579 		       L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
580   InitializeObjectAttributes(&ObjectAttributes,
581 			     &KeyName,
582 			     OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
583 			     0,
584 			     NULL);
585   Status = ZwCreateKey(&ResourceMapKey,
586 		       KEY_ALL_ACCESS,
587 		       &ObjectAttributes,
588 		       0,
589 		       NULL,
590 		       REG_OPTION_VOLATILE,
591 		       &Disposition);
592   if (!NT_SUCCESS(Status))
593       return Status;
594 
595   RtlInitUnicodeString(&KeyName, Level1Key);
596   InitializeObjectAttributes(&ObjectAttributes,
597 			     &KeyName,
598 			     OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
599 			     ResourceMapKey,
600 			     NULL);
601   Status = ZwCreateKey(&PnpMgrLevel1,
602                        KEY_ALL_ACCESS,
603                        &ObjectAttributes,
604                        0,
605                        NULL,
606                        REG_OPTION_VOLATILE,
607                        &Disposition);
608   ZwClose(ResourceMapKey);
609   if (!NT_SUCCESS(Status))
610       return Status;
611 
612   RtlInitUnicodeString(&KeyName, Level2Key);
613   InitializeObjectAttributes(&ObjectAttributes,
614 			     &KeyName,
615 			     OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
616 			     PnpMgrLevel1,
617 			     NULL);
618   Status = ZwCreateKey(&PnpMgrLevel2,
619                        KEY_ALL_ACCESS,
620                        &ObjectAttributes,
621                        0,
622                        NULL,
623                        REG_OPTION_VOLATILE,
624                        &Disposition);
625   ZwClose(PnpMgrLevel1);
626   if (!NT_SUCCESS(Status))
627       return Status;
628 
629   if (DeviceNode->ResourceList)
630   {
631       UNICODE_STRING NameU;
632       UNICODE_STRING RawSuffix, TranslatedSuffix;
633       ULONG OldLength = 0;
634 
635       ASSERT(DeviceNode->ResourceListTranslated);
636 
637       RtlInitUnicodeString(&TranslatedSuffix, L".Translated");
638       RtlInitUnicodeString(&RawSuffix, L".Raw");
639 
640       Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
641                                    DevicePropertyPhysicalDeviceObjectName,
642                                    0,
643                                    NULL,
644                                    &OldLength);
645       if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
646       {
647           ASSERT(OldLength);
648 
649           NameU.Buffer = ExAllocatePool(PagedPool, OldLength + TranslatedSuffix.Length);
650           if (!NameU.Buffer)
651           {
652               ZwClose(PnpMgrLevel2);
653               return STATUS_INSUFFICIENT_RESOURCES;
654           }
655 
656           NameU.Length = 0;
657           NameU.MaximumLength = (USHORT)OldLength + TranslatedSuffix.Length;
658 
659           Status = IoGetDeviceProperty(DeviceNode->PhysicalDeviceObject,
660                                        DevicePropertyPhysicalDeviceObjectName,
661                                        NameU.MaximumLength,
662                                        NameU.Buffer,
663                                        &OldLength);
664           if (!NT_SUCCESS(Status))
665           {
666               ZwClose(PnpMgrLevel2);
667               ExFreePool(NameU.Buffer);
668               return Status;
669           }
670       }
671       else if (!NT_SUCCESS(Status))
672       {
673           /* Some failure */
674           ZwClose(PnpMgrLevel2);
675           return Status;
676       }
677       else
678       {
679           /* This should never happen */
680           ASSERT(FALSE);
681       }
682 
683       NameU.Length = (USHORT)OldLength;
684 
685       RtlAppendUnicodeStringToString(&NameU, &RawSuffix);
686 
687       Status = ZwSetValueKey(PnpMgrLevel2,
688                              &NameU,
689                              0,
690                              REG_RESOURCE_LIST,
691                              DeviceNode->ResourceList,
692                              PnpDetermineResourceListSize(DeviceNode->ResourceList));
693       if (!NT_SUCCESS(Status))
694       {
695           ZwClose(PnpMgrLevel2);
696           ExFreePool(NameU.Buffer);
697           return Status;
698       }
699 
700       /* "Remove" the suffix by setting the length back to what it used to be */
701       NameU.Length = (USHORT)OldLength;
702 
703       RtlAppendUnicodeStringToString(&NameU, &TranslatedSuffix);
704 
705       Status = ZwSetValueKey(PnpMgrLevel2,
706                              &NameU,
707                              0,
708                              REG_RESOURCE_LIST,
709                              DeviceNode->ResourceListTranslated,
710                              PnpDetermineResourceListSize(DeviceNode->ResourceListTranslated));
711       ZwClose(PnpMgrLevel2);
712       ExFreePool(NameU.Buffer);
713 
714       if (!NT_SUCCESS(Status))
715           return Status;
716   }
717   else
718   {
719       ZwClose(PnpMgrLevel2);
720   }
721 
722   return STATUS_SUCCESS;
723 }
724 
725 NTSTATUS
726 IopUpdateResourceMapForPnPDevice(IN PDEVICE_NODE DeviceNode)
727 {
728   return IopUpdateResourceMap(DeviceNode, L"PnP Manager", L"PnpManager");
729 }
730 
731 static
732 NTSTATUS
733 IopTranslateDeviceResources(
734    IN PDEVICE_NODE DeviceNode)
735 {
736    PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
737    PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw, DescriptorTranslated;
738    ULONG i, j, ListSize;
739    NTSTATUS Status;
740 
741    if (!DeviceNode->ResourceList)
742    {
743       DeviceNode->ResourceListTranslated = NULL;
744       return STATUS_SUCCESS;
745    }
746 
747    /* That's easy to translate a resource list. Just copy the
748     * untranslated one and change few fields in the copy
749     */
750    ListSize = PnpDetermineResourceListSize(DeviceNode->ResourceList);
751 
752    DeviceNode->ResourceListTranslated = ExAllocatePool(PagedPool, ListSize);
753    if (!DeviceNode->ResourceListTranslated)
754    {
755       Status = STATUS_NO_MEMORY;
756       goto cleanup;
757    }
758    RtlCopyMemory(DeviceNode->ResourceListTranslated, DeviceNode->ResourceList, ListSize);
759 
760    for (i = 0; i < DeviceNode->ResourceList->Count; i++)
761    {
762       pPartialResourceList = &DeviceNode->ResourceList->List[i].PartialResourceList;
763       for (j = 0; j < pPartialResourceList->Count; j++)
764       {
765          DescriptorRaw = &pPartialResourceList->PartialDescriptors[j];
766          DescriptorTranslated = &DeviceNode->ResourceListTranslated->List[i].PartialResourceList.PartialDescriptors[j];
767          switch (DescriptorRaw->Type)
768          {
769             case CmResourceTypePort:
770             {
771                ULONG AddressSpace = 1; /* IO space */
772                if (!HalTranslateBusAddress(
773                   DeviceNode->ResourceList->List[i].InterfaceType,
774                   DeviceNode->ResourceList->List[i].BusNumber,
775                   DescriptorRaw->u.Port.Start,
776                   &AddressSpace,
777                   &DescriptorTranslated->u.Port.Start))
778                {
779                   Status = STATUS_UNSUCCESSFUL;
780                   DPRINT1("Failed to translate port resource (Start: 0x%I64x)\n", DescriptorRaw->u.Port.Start.QuadPart);
781                   goto cleanup;
782                }
783 
784                if (AddressSpace == 0)
785                {
786                    DPRINT1("Guessed incorrect address space: 1 -> 0\n");
787 
788                    /* FIXME: I think all other CM_RESOURCE_PORT_XXX flags are
789                     * invalid for this state but I'm not 100% sure */
790                    DescriptorRaw->Flags =
791                    DescriptorTranslated->Flags = CM_RESOURCE_PORT_MEMORY;
792                }
793                break;
794             }
795             case CmResourceTypeInterrupt:
796             {
797                DescriptorTranslated->u.Interrupt.Vector = HalGetInterruptVector(
798                   DeviceNode->ResourceList->List[i].InterfaceType,
799                   DeviceNode->ResourceList->List[i].BusNumber,
800                   DescriptorRaw->u.Interrupt.Level,
801                   DescriptorRaw->u.Interrupt.Vector,
802                   (PKIRQL)&DescriptorTranslated->u.Interrupt.Level,
803                   &DescriptorTranslated->u.Interrupt.Affinity);
804 
805                if (!DescriptorTranslated->u.Interrupt.Vector)
806                {
807                    Status = STATUS_UNSUCCESSFUL;
808                    DPRINT1("Failed to translate interrupt resource (Vector: 0x%x | Level: 0x%x)\n", DescriptorRaw->u.Interrupt.Vector,
809                                                                                                    DescriptorRaw->u.Interrupt.Level);
810                    goto cleanup;
811                }
812                break;
813             }
814             case CmResourceTypeMemory:
815             {
816                ULONG AddressSpace = 0; /* Memory space */
817                if (!HalTranslateBusAddress(
818                   DeviceNode->ResourceList->List[i].InterfaceType,
819                   DeviceNode->ResourceList->List[i].BusNumber,
820                   DescriptorRaw->u.Memory.Start,
821                   &AddressSpace,
822                   &DescriptorTranslated->u.Memory.Start))
823                {
824                   Status = STATUS_UNSUCCESSFUL;
825                   DPRINT1("Failed to translate memory resource (Start: 0x%I64x)\n", DescriptorRaw->u.Memory.Start.QuadPart);
826                   goto cleanup;
827                }
828 
829                if (AddressSpace != 0)
830                {
831                    DPRINT1("Guessed incorrect address space: 0 -> 1\n");
832 
833                    /* This should never happen for memory space */
834                    ASSERT(FALSE);
835                }
836             }
837 
838             case CmResourceTypeDma:
839             case CmResourceTypeBusNumber:
840             case CmResourceTypeDeviceSpecific:
841                /* Nothing to do */
842                break;
843             default:
844                DPRINT1("Unknown resource descriptor type 0x%x\n", DescriptorRaw->Type);
845                Status = STATUS_NOT_IMPLEMENTED;
846                goto cleanup;
847          }
848       }
849    }
850    return STATUS_SUCCESS;
851 
852 cleanup:
853    /* Yes! Also delete ResourceList because ResourceList and
854     * ResourceListTranslated should be a pair! */
855    ExFreePool(DeviceNode->ResourceList);
856    DeviceNode->ResourceList = NULL;
857    if (DeviceNode->ResourceListTranslated)
858    {
859       ExFreePool(DeviceNode->ResourceListTranslated);
860       DeviceNode->ResourceList = NULL;
861    }
862    return Status;
863 }
864 
865 NTSTATUS
866 NTAPI
867 IopAssignDeviceResources(
868    IN PDEVICE_NODE DeviceNode)
869 {
870    NTSTATUS Status;
871    ULONG ListSize;
872 
873    IopDeviceNodeSetFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
874 
875    Status = IopFilterResourceRequirements(DeviceNode);
876    if (!NT_SUCCESS(Status))
877        goto ByeBye;
878 
879    if (!DeviceNode->BootResources && !DeviceNode->ResourceRequirements)
880    {
881       DeviceNode->Flags |= DNF_NO_RESOURCE_REQUIRED;
882       DeviceNode->Flags &= ~DNF_ASSIGNING_RESOURCES;
883 
884       /* No resource needed for this device */
885       DeviceNode->ResourceList = NULL;
886       DeviceNode->ResourceListTranslated = NULL;
887 
888       return STATUS_SUCCESS;
889    }
890 
891    /* Fill DeviceNode->ResourceList
892     * FIXME: the PnP arbiter should go there!
893     * Actually, use the BootResources if provided, else the resource requirements
894     */
895 
896    if (DeviceNode->BootResources)
897    {
898       ListSize = PnpDetermineResourceListSize(DeviceNode->BootResources);
899 
900       DeviceNode->ResourceList = ExAllocatePool(PagedPool, ListSize);
901       if (!DeviceNode->ResourceList)
902       {
903          Status = STATUS_NO_MEMORY;
904          goto ByeBye;
905       }
906       RtlCopyMemory(DeviceNode->ResourceList, DeviceNode->BootResources, ListSize);
907 
908       Status = IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL);
909       if (NT_SUCCESS(Status) || !DeviceNode->ResourceRequirements)
910       {
911           if (!NT_SUCCESS(Status) && !DeviceNode->ResourceRequirements)
912           {
913               DPRINT1("Using conflicting boot resources because no requirements were supplied!\n");
914           }
915 
916           goto Finish;
917       }
918       else
919       {
920           DPRINT1("Boot resources for %wZ cause a resource conflict!\n", &DeviceNode->InstancePath);
921           ExFreePool(DeviceNode->ResourceList);
922           DeviceNode->ResourceList = NULL;
923       }
924    }
925 
926    Status = IopCreateResourceListFromRequirements(DeviceNode->ResourceRequirements,
927                                                   &DeviceNode->ResourceList);
928    if (!NT_SUCCESS(Status))
929    {
930        DPRINT1("Failed to create a resource list from supplied resources for %wZ\n", &DeviceNode->InstancePath);
931        goto ByeBye;
932    }
933 
934    /* IopCreateResourceListFromRequirements should NEVER succeed with a conflicting list */
935    ASSERT(IopDetectResourceConflict(DeviceNode->ResourceList, FALSE, NULL) != STATUS_CONFLICTING_ADDRESSES);
936 
937 Finish:
938    Status = IopTranslateDeviceResources(DeviceNode);
939    if (!NT_SUCCESS(Status))
940    {
941        DPRINT1("Failed to translate resources for %wZ\n", &DeviceNode->InstancePath);
942        goto ByeBye;
943    }
944 
945    Status = IopUpdateResourceMapForPnPDevice(DeviceNode);
946    if (!NT_SUCCESS(Status))
947        goto ByeBye;
948 
949    Status = IopUpdateControlKeyWithResources(DeviceNode);
950    if (!NT_SUCCESS(Status))
951        goto ByeBye;
952 
953    IopDeviceNodeSetFlag(DeviceNode, DNF_RESOURCE_ASSIGNED);
954 
955    IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
956 
957    return STATUS_SUCCESS;
958 
959 ByeBye:
960    if (DeviceNode->ResourceList)
961    {
962       ExFreePool(DeviceNode->ResourceList);
963       DeviceNode->ResourceList = NULL;
964    }
965 
966    DeviceNode->ResourceListTranslated = NULL;
967 
968    IopDeviceNodeClearFlag(DeviceNode, DNF_ASSIGNING_RESOURCES);
969 
970    return Status;
971 }
972 
973 static
974 BOOLEAN
975 IopCheckForResourceConflict(
976    IN PCM_RESOURCE_LIST ResourceList1,
977    IN PCM_RESOURCE_LIST ResourceList2,
978    IN BOOLEAN Silent,
979    OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
980 {
981    ULONG i, ii;
982    BOOLEAN Result = FALSE;
983 
984    for (i = 0; i < ResourceList1->Count; i++)
985    {
986       PCM_PARTIAL_RESOURCE_LIST ResList = &ResourceList1->List[i].PartialResourceList;
987       for (ii = 0; ii < ResList->Count; ii++)
988       {
989          PCM_PARTIAL_RESOURCE_DESCRIPTOR ResDesc = &ResList->PartialDescriptors[ii];
990 
991          Result = IopCheckResourceDescriptor(ResDesc,
992                                              ResourceList2,
993                                              Silent,
994                                              ConflictingDescriptor);
995          if (Result) goto ByeBye;
996       }
997    }
998 
999 ByeBye:
1000 
1001    return Result;
1002 }
1003 
1004 NTSTATUS NTAPI
1005 IopDetectResourceConflict(
1006    IN PCM_RESOURCE_LIST ResourceList,
1007    IN BOOLEAN Silent,
1008    OUT OPTIONAL PCM_PARTIAL_RESOURCE_DESCRIPTOR ConflictingDescriptor)
1009 {
1010    OBJECT_ATTRIBUTES ObjectAttributes;
1011    UNICODE_STRING KeyName;
1012    HANDLE ResourceMapKey = INVALID_HANDLE_VALUE, ChildKey2 = INVALID_HANDLE_VALUE, ChildKey3 = INVALID_HANDLE_VALUE;
1013    ULONG KeyInformationLength, RequiredLength, KeyValueInformationLength, KeyNameInformationLength;
1014    PKEY_BASIC_INFORMATION KeyInformation;
1015    PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
1016    PKEY_VALUE_BASIC_INFORMATION KeyNameInformation;
1017    ULONG ChildKeyIndex1 = 0, ChildKeyIndex2 = 0, ChildKeyIndex3 = 0;
1018    NTSTATUS Status;
1019 
1020    RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE\\RESOURCEMAP");
1021    InitializeObjectAttributes(&ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL);
1022    Status = ZwOpenKey(&ResourceMapKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1023    if (!NT_SUCCESS(Status))
1024    {
1025       /* The key is missing which means we are the first device */
1026       return STATUS_SUCCESS;
1027    }
1028 
1029    while (TRUE)
1030    {
1031       Status = ZwEnumerateKey(ResourceMapKey,
1032                               ChildKeyIndex1,
1033                               KeyBasicInformation,
1034                               NULL,
1035                               0,
1036                               &RequiredLength);
1037       if (Status == STATUS_NO_MORE_ENTRIES)
1038           break;
1039       else if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
1040       {
1041           KeyInformationLength = RequiredLength;
1042           KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1043           if (!KeyInformation)
1044           {
1045               Status = STATUS_INSUFFICIENT_RESOURCES;
1046               goto cleanup;
1047           }
1048 
1049           Status = ZwEnumerateKey(ResourceMapKey,
1050                                   ChildKeyIndex1,
1051                                   KeyBasicInformation,
1052                                   KeyInformation,
1053                                   KeyInformationLength,
1054                                   &RequiredLength);
1055       }
1056       else
1057          goto cleanup;
1058       ChildKeyIndex1++;
1059       if (!NT_SUCCESS(Status))
1060           goto cleanup;
1061 
1062       KeyName.Buffer = KeyInformation->Name;
1063       KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
1064       InitializeObjectAttributes(&ObjectAttributes,
1065                                  &KeyName,
1066                                  OBJ_CASE_INSENSITIVE,
1067                                  ResourceMapKey,
1068                                  NULL);
1069       Status = ZwOpenKey(&ChildKey2, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &ObjectAttributes);
1070       ExFreePool(KeyInformation);
1071       if (!NT_SUCCESS(Status))
1072           goto cleanup;
1073 
1074       while (TRUE)
1075       {
1076           Status = ZwEnumerateKey(ChildKey2,
1077                                   ChildKeyIndex2,
1078                                   KeyBasicInformation,
1079                                   NULL,
1080                                   0,
1081                                   &RequiredLength);
1082           if (Status == STATUS_NO_MORE_ENTRIES)
1083               break;
1084           else if (Status == STATUS_BUFFER_TOO_SMALL)
1085           {
1086               KeyInformationLength = RequiredLength;
1087               KeyInformation = ExAllocatePool(PagedPool, KeyInformationLength);
1088               if (!KeyInformation)
1089               {
1090                   Status = STATUS_INSUFFICIENT_RESOURCES;
1091                   goto cleanup;
1092               }
1093 
1094               Status = ZwEnumerateKey(ChildKey2,
1095                                       ChildKeyIndex2,
1096                                       KeyBasicInformation,
1097                                       KeyInformation,
1098                                       KeyInformationLength,
1099                                       &RequiredLength);
1100           }
1101           else
1102               goto cleanup;
1103           ChildKeyIndex2++;
1104           if (!NT_SUCCESS(Status))
1105               goto cleanup;
1106 
1107           KeyName.Buffer = KeyInformation->Name;
1108           KeyName.MaximumLength = KeyName.Length = (USHORT)KeyInformation->NameLength;
1109           InitializeObjectAttributes(&ObjectAttributes,
1110                                      &KeyName,
1111                                      OBJ_CASE_INSENSITIVE,
1112                                      ChildKey2,
1113                                      NULL);
1114           Status = ZwOpenKey(&ChildKey3, KEY_QUERY_VALUE, &ObjectAttributes);
1115           ExFreePool(KeyInformation);
1116           if (!NT_SUCCESS(Status))
1117               goto cleanup;
1118 
1119           while (TRUE)
1120           {
1121               Status = ZwEnumerateValueKey(ChildKey3,
1122                                            ChildKeyIndex3,
1123                                            KeyValuePartialInformation,
1124                                            NULL,
1125                                            0,
1126                                            &RequiredLength);
1127               if (Status == STATUS_NO_MORE_ENTRIES)
1128                   break;
1129               else if (Status == STATUS_BUFFER_TOO_SMALL)
1130               {
1131                   KeyValueInformationLength = RequiredLength;
1132                   KeyValueInformation = ExAllocatePool(PagedPool, KeyValueInformationLength);
1133                   if (!KeyValueInformation)
1134                   {
1135                       Status = STATUS_INSUFFICIENT_RESOURCES;
1136                       goto cleanup;
1137                   }
1138 
1139                   Status = ZwEnumerateValueKey(ChildKey3,
1140                                                ChildKeyIndex3,
1141                                                KeyValuePartialInformation,
1142                                                KeyValueInformation,
1143                                                KeyValueInformationLength,
1144                                                &RequiredLength);
1145               }
1146               else
1147                   goto cleanup;
1148               if (!NT_SUCCESS(Status))
1149                   goto cleanup;
1150 
1151               Status = ZwEnumerateValueKey(ChildKey3,
1152                                            ChildKeyIndex3,
1153                                            KeyValueBasicInformation,
1154                                            NULL,
1155                                            0,
1156                                            &RequiredLength);
1157               if (Status == STATUS_BUFFER_TOO_SMALL)
1158               {
1159                   KeyNameInformationLength = RequiredLength;
1160                   KeyNameInformation = ExAllocatePool(PagedPool, KeyNameInformationLength + sizeof(WCHAR));
1161                   if (!KeyNameInformation)
1162                   {
1163                       Status = STATUS_INSUFFICIENT_RESOURCES;
1164                       goto cleanup;
1165                   }
1166 
1167                   Status = ZwEnumerateValueKey(ChildKey3,
1168                                                ChildKeyIndex3,
1169                                                KeyValueBasicInformation,
1170                                                KeyNameInformation,
1171                                                KeyNameInformationLength,
1172                                                &RequiredLength);
1173               }
1174               else
1175                   goto cleanup;
1176 
1177               ChildKeyIndex3++;
1178 
1179               if (!NT_SUCCESS(Status))
1180                   goto cleanup;
1181 
1182               KeyNameInformation->Name[KeyNameInformation->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
1183 
1184               /* Skip translated entries */
1185               if (wcsstr(KeyNameInformation->Name, L".Translated"))
1186               {
1187                   ExFreePool(KeyNameInformation);
1188                   continue;
1189               }
1190 
1191               ExFreePool(KeyNameInformation);
1192 
1193               if (IopCheckForResourceConflict(ResourceList,
1194                                               (PCM_RESOURCE_LIST)KeyValueInformation->Data,
1195                                               Silent,
1196                                               ConflictingDescriptor))
1197               {
1198                   ExFreePool(KeyValueInformation);
1199                   Status = STATUS_CONFLICTING_ADDRESSES;
1200                   goto cleanup;
1201               }
1202 
1203               ExFreePool(KeyValueInformation);
1204           }
1205       }
1206    }
1207 
1208 cleanup:
1209    if (ResourceMapKey != INVALID_HANDLE_VALUE)
1210        ZwClose(ResourceMapKey);
1211    if (ChildKey2 != INVALID_HANDLE_VALUE)
1212        ZwClose(ChildKey2);
1213    if (ChildKey3 != INVALID_HANDLE_VALUE)
1214        ZwClose(ChildKey3);
1215 
1216    if (Status == STATUS_NO_MORE_ENTRIES)
1217        Status = STATUS_SUCCESS;
1218 
1219    return Status;
1220 }
1221 
1222