xref: /reactos/hal/halx86/generic/usage.c (revision 84344399)
1 /*
2  * PROJECT:         ReactOS HAL
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         HAL Resource Report Routines
5  * PROGRAMMERS:     Stefan Ginsberg (stefan.ginsberg@reactos.org)
6  */
7 
8 /* INCLUDES *******************************************************************/
9 
10 #include <hal.h>
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS ********************************************************************/
16 
17 BOOLEAN HalpGetInfoFromACPI;
18 BOOLEAN HalpNMIDumpFlag;
19 PUCHAR KdComPortInUse;
20 PADDRESS_USAGE HalpAddressUsageList;
21 IDTUsageFlags HalpIDTUsageFlags[MAXIMUM_IDTVECTOR+1];
22 IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR+1];
23 
24 USHORT HalpComPortIrqMapping[5][2] =
25 {
26     {0x3F8, 4},
27     {0x2F8, 3},
28     {0x3E8, 4},
29     {0x2E8, 3},
30     {0, 0}
31 };
32 
33 ADDRESS_USAGE HalpComIoSpace =
34 {
35     NULL, CmResourceTypePort, IDT_INTERNAL,
36     {
37         {0x2F8,   0x8},     /* COM 1 */
38         {0,0},
39     }
40 };
41 
42 ADDRESS_USAGE HalpDefaultIoSpace =
43 {
44     NULL, CmResourceTypePort, IDT_INTERNAL,
45     {
46 #if defined(SARCH_PC98)
47         /* PIC 1 */
48         {0x00,  1},
49         {0x02,  1},
50         /* PIC 2 */
51         {0x08,  1},
52         {0x0A,  1},
53         /* DMA */
54         {0x01,  1},
55         {0x03,  1},
56         {0x05,  1},
57         {0x07,  1},
58         {0x09,  1},
59         {0x0B,  1},
60         {0x0D,  1},
61         {0x0F,  1},
62         {0x11,  1},
63         {0x13,  1},
64         {0x15,  1},
65         {0x17,  1},
66         {0x19,  1},
67         {0x1B,  1},
68         {0x1D,  1},
69         {0x1F,  1},
70         {0x21,  1},
71         {0x23,  1},
72         {0x25,  1},
73         {0x27,  1},
74         {0x29,  1},
75         {0x2B,  1},
76         {0x2D,  1},
77         {0xE05, 1},
78         {0xE07, 1},
79         {0xE09, 1},
80         {0xE0B, 1},
81         /* RTC */
82         {0x20,  1},
83         {0x22,  1},
84         {0x128, 1},
85         /* System Control */
86         {0x33,  1},
87         {0x37,  1},
88         /* PIT */
89         {0x71,  1},
90         {0x73,  1},
91         {0x75,  1},
92         {0x77,  1},
93         {0x3FD9,1},
94         {0x3FDB,1},
95         {0x3FDD,1},
96         {0x3FDF,1},
97         /* x87 Coprocessor */
98         {0xF8,  8},
99 #else
100         {0x00,  0x20}, /* DMA 1 */
101         {0xC0,  0x20}, /* DMA 2 */
102         {0x80,  0x10}, /* DMA EPAR */
103         {0x20,  0x2},  /* PIC 1 */
104         {0xA0,  0x2},  /* PIC 2 */
105         {0x40,  0x4},  /* PIT 1 */
106         {0x48,  0x4},  /* PIT 2 */
107         {0x92,  0x1},  /* System Control Port A */
108         {0x70,  0x2},  /* CMOS  */
109         {0xF0,  0x10}, /* x87 Coprocessor */
110 #endif
111         {0xCF8, 0x8},  /* PCI 0 */
112         {0,0},
113     }
114 };
115 
116 /* FUNCTIONS ******************************************************************/
117 
118 #ifndef _MINIHAL_
119 CODE_SEG("INIT")
120 VOID
121 NTAPI
122 HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
123                          OUT PULONG Scale,
124                          OUT PLARGE_INTEGER Value)
125 {
126     /* Sorting depends on resource type */
127     switch (Descriptor->Type)
128     {
129         case CmResourceTypeInterrupt:
130 
131             /* Interrupt goes by level */
132             *Scale = 0;
133             *Value = RtlConvertUlongToLargeInteger(Descriptor->u.Interrupt.Level);
134             break;
135 
136         case CmResourceTypePort:
137 
138             /* Port goes by port address */
139             *Scale = 1;
140             *Value = Descriptor->u.Port.Start;
141             break;
142 
143         case CmResourceTypeMemory:
144 
145             /* Memory goes by base address */
146             *Scale = 2;
147             *Value = Descriptor->u.Memory.Start;
148             break;
149 
150         default:
151 
152             /* Anything else */
153             *Scale = 4;
154             *Value = RtlConvertUlongToLargeInteger(0);
155             break;
156     }
157 }
158 
159 CODE_SEG("INIT")
160 VOID
161 NTAPI
162 HalpBuildPartialFromIdt(IN ULONG Entry,
163                         IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor,
164                         IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor)
165 {
166     /* Exclusive interrupt entry */
167     RawDescriptor->Type = CmResourceTypeInterrupt;
168     RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
169 
170     /* Check the interrupt type */
171     if (HalpIDTUsageFlags[Entry].Flags & IDT_LATCHED)
172     {
173         /* Latched */
174         RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
175     }
176     else
177     {
178         /* Level */
179         RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
180     }
181 
182     /* Get vector and level from IDT usage */
183     RawDescriptor->u.Interrupt.Vector = HalpIDTUsage[Entry].BusReleativeVector;
184     RawDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].BusReleativeVector;
185 
186     /* Affinity is all the CPUs */
187     RawDescriptor->u.Interrupt.Affinity = HalpActiveProcessors;
188 
189     /* The translated copy is identical */
190     RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
191 
192     /* But the vector and IRQL must be set correctly */
193     TranslatedDescriptor->u.Interrupt.Vector = Entry;
194     TranslatedDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].Irql;
195 }
196 
197 CODE_SEG("INIT")
198 VOID
199 NTAPI
200 HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface,
201                             IN PADDRESS_USAGE CurrentAddress,
202                             IN ULONG Element,
203                             IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor,
204                             IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor)
205 {
206     ULONG AddressSpace;
207 
208     /* Set the type and make it exclusive */
209     RawDescriptor->Type = CurrentAddress->Type;
210     RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
211 
212     /* Check what this is */
213     if (RawDescriptor->Type == CmResourceTypePort)
214     {
215         /* Write out port data */
216         AddressSpace = 1;
217         RawDescriptor->Flags = CM_RESOURCE_PORT_IO;
218         RawDescriptor->u.Port.Start.HighPart = 0;
219         RawDescriptor->u.Port.Start.LowPart = CurrentAddress->Element[Element].Start;
220         RawDescriptor->u.Port.Length = CurrentAddress->Element[Element].Length;
221 
222         /* Determine if 16-bit port addresses are allowed */
223         RawDescriptor->Flags |= HalpIs16BitPortDecodeSupported();
224     }
225     else
226     {
227         /* Write out memory data */
228         AddressSpace = 0;
229         RawDescriptor->Flags = (CurrentAddress->Flags & IDT_READ_ONLY) ?
230                                 CM_RESOURCE_MEMORY_READ_ONLY :
231                                 CM_RESOURCE_MEMORY_READ_WRITE;
232         RawDescriptor->u.Memory.Start.HighPart = 0;
233         RawDescriptor->u.Memory.Start.LowPart = CurrentAddress->Element[Element].Start;
234         RawDescriptor->u.Memory.Length = CurrentAddress->Element[Element].Length;
235     }
236 
237     /* Make an identical copy to begin with */
238     RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
239 
240     /* Check what this is */
241     if (RawDescriptor->Type == CmResourceTypePort)
242     {
243         /* Translate the port */
244         HalTranslateBusAddress(Interface,
245                                0,
246                                RawDescriptor->u.Port.Start,
247                                &AddressSpace,
248                                &TranslatedDescriptor->u.Port.Start);
249 
250         /* If it turns out this is memory once translated, flag it */
251         if (AddressSpace == 0) TranslatedDescriptor->Flags = CM_RESOURCE_PORT_MEMORY;
252 
253     }
254     else
255     {
256         /* Translate the memory */
257         HalTranslateBusAddress(Interface,
258                                0,
259                                RawDescriptor->u.Memory.Start,
260                                &AddressSpace,
261                                &TranslatedDescriptor->u.Memory.Start);
262     }
263 }
264 
265 CODE_SEG("INIT")
266 VOID
267 NTAPI
268 HalpReportResourceUsage(IN PUNICODE_STRING HalName,
269                         IN INTERFACE_TYPE InterfaceType)
270 {
271     PCM_RESOURCE_LIST RawList, TranslatedList;
272     PCM_FULL_RESOURCE_DESCRIPTOR RawFull, TranslatedFull;
273     PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw, CurrentTranslated, SortedRaw, SortedTranslated;
274     CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial, TranslatedPartial;
275     PCM_PARTIAL_RESOURCE_LIST RawPartialList = NULL, TranslatedPartialList = NULL;
276     INTERFACE_TYPE Interface;
277     ULONG i, j, k, ListSize, Count, Port, Element, CurrentScale, SortScale, ReportType, FlagMatch;
278     ADDRESS_USAGE *CurrentAddress;
279     LARGE_INTEGER CurrentSortValue, SortValue;
280     DbgPrint("%wZ Detected\n", HalName);
281 
282     /* Check if KD is using a COM port */
283     if (KdComPortInUse)
284     {
285         /* Enter it into the I/O space */
286         HalpComIoSpace.Element[0].Start = PtrToUlong(KdComPortInUse);
287         HalpComIoSpace.Next = HalpAddressUsageList;
288         HalpAddressUsageList = &HalpComIoSpace;
289 
290 #if defined(SARCH_XBOX)
291         /*
292          * Do not claim interrupt resources for the KD COM port.
293          * The actual COM port lacks SERIRQ, IRQ 4 is hardwired to the NIC.
294          */
295         UNREFERENCED_PARAMETER(Port);
296 #else
297         /* Use the debug port table if we have one */
298         HalpGetInfoFromACPI = HalpGetDebugPortTable();
299 
300         /* Check if we're using ACPI */
301         if (!HalpGetInfoFromACPI)
302         {
303             /* No, so use our local table */
304             for (i = 0, Port = HalpComPortIrqMapping[i][0];
305                  Port;
306                  i++, Port = HalpComPortIrqMapping[i][0])
307             {
308                 /* Is this the port we want? */
309                 if (Port == (ULONG_PTR)KdComPortInUse)
310                 {
311                     /* Register it */
312                     HalpRegisterVector(IDT_DEVICE | IDT_LATCHED,
313                                        HalpComPortIrqMapping[i][1],
314                                        HalpComPortIrqMapping[i][1] +
315                                        PRIMARY_VECTOR_BASE,
316                                        HIGH_LEVEL);
317                 }
318             }
319         }
320 #endif
321     }
322 
323     /* On non-ACPI systems, we need to build an address map */
324     HalpBuildAddressMap();
325 
326     /* Allocate the master raw and translated lists */
327     RawList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL);
328     TranslatedList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL);
329     if (!(RawList) || !(TranslatedList))
330     {
331         /* Bugcheck the system */
332         KeBugCheckEx(HAL_MEMORY_ALLOCATION,
333                      4 * PAGE_SIZE,
334                      1,
335                      (ULONG_PTR)__FILE__,
336                      __LINE__);
337     }
338 
339     /* Zero out the lists */
340     RtlZeroMemory(RawList, PAGE_SIZE * 2);
341     RtlZeroMemory(TranslatedList, PAGE_SIZE * 2);
342 
343     /* Set the interface type to begin with */
344     RawList->List[0].InterfaceType = InterfaceTypeUndefined;
345 
346     /* Loop all IDT entries that are not IRQs */
347     for (i = 0; i < PRIMARY_VECTOR_BASE; i++)
348     {
349         /* Check if the IDT isn't owned */
350         if (!(HalpIDTUsageFlags[i].Flags & IDT_REGISTERED))
351         {
352             /* Then register it for internal usage */
353             HalpIDTUsageFlags[i].Flags = IDT_INTERNAL;
354             HalpIDTUsage[i].BusReleativeVector = (UCHAR)i;
355         }
356     }
357 
358     /* Our full raw descriptors start here */
359     RawFull = RawList->List;
360 
361     /* Keep track of the current partial raw and translated descriptors */
362     CurrentRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)RawList->List;
363     CurrentTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)TranslatedList->List;
364 
365     /* Do two passes */
366     for (ReportType = 0; ReportType < 2; ReportType++)
367     {
368         /* Pass 0 is for device usage */
369         if (ReportType == 0)
370         {
371             FlagMatch = IDT_DEVICE & ~IDT_REGISTERED;
372             Interface = InterfaceType;
373         }
374         else
375         {
376             /* Past 1 is for internal HAL usage */
377             FlagMatch = IDT_INTERNAL & ~IDT_REGISTERED;
378             Interface = Internal;
379         }
380 
381         /* Reset loop variables */
382         i = Element = 0;
383 
384         /* Start looping our address uage list and interrupts */
385         CurrentAddress = HalpAddressUsageList;
386         while (TRUE)
387         {
388             /* Check for valid vector number */
389             if (i <= MAXIMUM_IDTVECTOR)
390             {
391                 /* Check if this entry should be parsed */
392                 if ((HalpIDTUsageFlags[i].Flags & FlagMatch))
393                 {
394                     /* Parse it */
395                     HalpBuildPartialFromIdt(i, &RawPartial, &TranslatedPartial);
396                     i++;
397                 }
398                 else
399                 {
400                     /* Skip this entry */
401                     i++;
402                     continue;
403                 }
404             }
405             else
406             {
407                 /* This is an address instead */
408                 if (!CurrentAddress) break;
409 
410                 /* Check if the address should be reported */
411                 if (!(CurrentAddress->Flags & FlagMatch) ||
412                     !(CurrentAddress->Element[Element].Length))
413                 {
414                     /* Nope, skip it */
415                     Element = 0;
416                     CurrentAddress = CurrentAddress->Next;
417                     continue;
418                 }
419 
420                 /* Otherwise, parse the entry */
421                 HalpBuildPartialFromAddress(Interface,
422                                             CurrentAddress,
423                                             Element,
424                                             &RawPartial,
425                                             &TranslatedPartial);
426                 Element++;
427             }
428 
429             /* Check for interface change */
430             if (RawFull->InterfaceType != Interface)
431             {
432                 /* We need to add another full descriptor */
433                 RawList->Count++;
434                 TranslatedList->Count++;
435 
436                 /* The full descriptor follows wherever we were */
437                 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
438                 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
439 
440                 /* And it is of this new interface type */
441                 RawFull->InterfaceType = Interface;
442                 TranslatedFull->InterfaceType = Interface;
443 
444                 /* And its partial descriptors begin here */
445                 RawPartialList = &RawFull->PartialResourceList;
446                 TranslatedPartialList = &TranslatedFull->PartialResourceList;
447 
448                 /* And our next full descriptor should follow here */
449                 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
450                 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
451             }
452 
453             /* We have written a new partial descriptor */
454             RawPartialList->Count++;
455             TranslatedPartialList->Count++;
456 
457             /* Copy our local descriptors into the actual list */
458             RtlCopyMemory(CurrentRaw, &RawPartial, sizeof(RawPartial));
459             RtlCopyMemory(CurrentTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
460 
461             /* Move to the next partial descriptor */
462             CurrentRaw++;
463             CurrentTranslated++;
464         }
465     }
466 
467     /* Get the final list of the size for the kernel call later */
468     ListSize = (ULONG)((ULONG_PTR)CurrentRaw - (ULONG_PTR)RawList);
469 
470     /* Now reset back to the first full descriptor */
471     RawFull = RawList->List;
472     TranslatedFull = TranslatedList->List;
473 
474     /* And loop all the full descriptors */
475     for (i = 0; i < RawList->Count; i++)
476     {
477         /* Get the first partial descriptor in this list */
478         CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
479         CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
480 
481         /* Get the count of partials in this list */
482         Count = RawFull->PartialResourceList.Count;
483 
484         /* Loop all the partials in this list */
485         for (j = 0; j < Count; j++)
486         {
487             /* Get the sort value at this point */
488             HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
489 
490             /* Save the current sort pointer */
491             SortedRaw = CurrentRaw;
492             SortedTranslated = CurrentTranslated;
493 
494             /* Loop all descriptors starting from this one */
495             for (k = j; k < Count; k++)
496             {
497                 /* Get the sort value at the sort point */
498                 HalpGetResourceSortValue(SortedRaw, &SortScale, &SortValue);
499 
500                 /* Check if a swap needs to occur */
501                 if ((SortScale < CurrentScale) ||
502                     ((SortScale == CurrentScale) &&
503                      (SortValue.QuadPart <= CurrentSortValue.QuadPart)))
504                 {
505                     /* Swap raw partial with the sort location partial */
506                     RtlCopyMemory(&RawPartial, CurrentRaw, sizeof(RawPartial));
507                     RtlCopyMemory(CurrentRaw, SortedRaw, sizeof(RawPartial));
508                     RtlCopyMemory(SortedRaw, &RawPartial, sizeof(RawPartial));
509 
510                     /* Swap translated partial in the same way */
511                     RtlCopyMemory(&TranslatedPartial, CurrentTranslated, sizeof(TranslatedPartial));
512                     RtlCopyMemory(CurrentTranslated, SortedTranslated, sizeof(TranslatedPartial));
513                     RtlCopyMemory(SortedTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
514 
515                     /* Update the sort value at this point */
516                     HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
517                 }
518 
519                 /* The sort location has been updated */
520                 SortedRaw++;
521                 SortedTranslated++;
522             }
523 
524             /* Move to the next partial */
525             CurrentRaw++;
526             CurrentTranslated++;
527         }
528 
529         /* Move to the next full descriptor */
530         RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
531         TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
532     }
533 
534     /* Mark this is an ACPI system, if it is */
535     HalpMarkAcpiHal();
536 
537     /* Tell the kernel about all this */
538     IoReportHalResourceUsage(HalName,
539                              RawList,
540                              TranslatedList,
541                              ListSize);
542 
543     /* Free our lists */
544     ExFreePool(RawList);
545     ExFreePool(TranslatedList);
546 
547     /* Get the machine's serial number */
548     HalpReportSerialNumber();
549 }
550 #endif /* !_MINIHAL_ */
551 
552 CODE_SEG("INIT")
553 VOID
554 NTAPI
555 HalpRegisterVector(IN UCHAR Flags,
556                    IN ULONG BusVector,
557                    IN ULONG SystemVector,
558                    IN KIRQL Irql)
559 {
560     /* Save the vector flags */
561     HalpIDTUsageFlags[SystemVector].Flags = Flags;
562 
563     /* Save the vector data */
564     HalpIDTUsage[SystemVector].Irql  = Irql;
565     HalpIDTUsage[SystemVector].BusReleativeVector = (UCHAR)BusVector;
566 }
567 
568 #ifndef _MINIHAL_
569 CODE_SEG("INIT")
570 VOID
571 NTAPI
572 HalpEnableInterruptHandler(IN UCHAR Flags,
573                            IN ULONG BusVector,
574                            IN ULONG SystemVector,
575                            IN KIRQL Irql,
576                            IN PVOID Handler,
577                            IN KINTERRUPT_MODE Mode)
578 {
579     /* Set the IDT_LATCHED flag for latched interrupts */
580     if (Mode == Latched) Flags |= IDT_LATCHED;
581 
582     /* Register the vector */
583     HalpRegisterVector(Flags, BusVector, SystemVector, Irql);
584 
585     /* Connect the interrupt */
586     KeRegisterInterruptHandler(SystemVector, Handler);
587 
588     /* Enable the interrupt */
589     HalEnableSystemInterrupt(SystemVector, Irql, Mode);
590 }
591 
592 CODE_SEG("INIT")
593 VOID
594 NTAPI
595 HalpGetNMICrashFlag(VOID)
596 {
597     UNICODE_STRING ValueName;
598     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
599     OBJECT_ATTRIBUTES ObjectAttributes;
600     ULONG ResultLength;
601     HANDLE Handle;
602     NTSTATUS Status;
603     KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
604 
605     /* Set default */
606     HalpNMIDumpFlag = 0;
607 
608     /* Initialize attributes */
609     InitializeObjectAttributes(&ObjectAttributes,
610                                &KeyName,
611                                OBJ_CASE_INSENSITIVE,
612                                NULL,
613                                NULL);
614 
615     /* Open crash key */
616     Status = ZwOpenKey(&Handle, KEY_READ, &ObjectAttributes);
617     if (NT_SUCCESS(Status))
618     {
619         /* Query key value */
620         RtlInitUnicodeString(&ValueName, L"NMICrashDump");
621         Status = ZwQueryValueKey(Handle,
622                                  &ValueName,
623                                  KeyValuePartialInformation,
624                                  &KeyValueInformation,
625                                  sizeof(KeyValueInformation),
626                                  &ResultLength);
627         if (NT_SUCCESS(Status))
628         {
629             /* Check for valid data */
630             if (ResultLength == sizeof(KEY_VALUE_PARTIAL_INFORMATION))
631             {
632                 /* Read the flag */
633                 HalpNMIDumpFlag = KeyValueInformation.Data[0];
634             }
635         }
636 
637         /* We're done */
638         ZwClose(Handle);
639     }
640 }
641 #endif  /* !_MINIHAL_ */
642 
643 /* EOF */
644