xref: /reactos/hal/halx86/generic/usage.c (revision 6d8aafb6)
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         /* Use the debug port table if we have one */
291         HalpGetInfoFromACPI = HalpGetDebugPortTable();
292 
293         /* Check if we're using ACPI */
294         if (!HalpGetInfoFromACPI)
295         {
296             /* No, so use our local table */
297             for (i = 0, Port = HalpComPortIrqMapping[i][0];
298                  Port;
299                  i++, Port = HalpComPortIrqMapping[i][0])
300             {
301                 /* Is this the port we want? */
302                 if (Port == (ULONG_PTR)KdComPortInUse)
303                 {
304                     /* Register it */
305                     HalpRegisterVector(IDT_DEVICE | IDT_LATCHED,
306                                        HalpComPortIrqMapping[i][1],
307                                        HalpComPortIrqMapping[i][1] +
308                                        PRIMARY_VECTOR_BASE,
309                                        HIGH_LEVEL);
310                 }
311             }
312         }
313     }
314 
315     /* On non-ACPI systems, we need to build an address map */
316     HalpBuildAddressMap();
317 
318     /* Allocate the master raw and translated lists */
319     RawList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL);
320     TranslatedList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL);
321     if (!(RawList) || !(TranslatedList))
322     {
323         /* Bugcheck the system */
324         KeBugCheckEx(HAL_MEMORY_ALLOCATION,
325                      4 * PAGE_SIZE,
326                      1,
327                      (ULONG_PTR)__FILE__,
328                      __LINE__);
329     }
330 
331     /* Zero out the lists */
332     RtlZeroMemory(RawList, PAGE_SIZE * 2);
333     RtlZeroMemory(TranslatedList, PAGE_SIZE * 2);
334 
335     /* Set the interface type to begin with */
336     RawList->List[0].InterfaceType = InterfaceTypeUndefined;
337 
338     /* Loop all IDT entries that are not IRQs */
339     for (i = 0; i < PRIMARY_VECTOR_BASE; i++)
340     {
341         /* Check if the IDT isn't owned */
342         if (!(HalpIDTUsageFlags[i].Flags & IDT_REGISTERED))
343         {
344             /* Then register it for internal usage */
345             HalpIDTUsageFlags[i].Flags = IDT_INTERNAL;
346             HalpIDTUsage[i].BusReleativeVector = (UCHAR)i;
347         }
348     }
349 
350     /* Our full raw descriptors start here */
351     RawFull = RawList->List;
352 
353     /* Keep track of the current partial raw and translated descriptors */
354     CurrentRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)RawList->List;
355     CurrentTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)TranslatedList->List;
356 
357     /* Do two passes */
358     for (ReportType = 0; ReportType < 2; ReportType++)
359     {
360         /* Pass 0 is for device usage */
361         if (ReportType == 0)
362         {
363             FlagMatch = IDT_DEVICE & ~IDT_REGISTERED;
364             Interface = InterfaceType;
365         }
366         else
367         {
368             /* Past 1 is for internal HAL usage */
369             FlagMatch = IDT_INTERNAL & ~IDT_REGISTERED;
370             Interface = Internal;
371         }
372 
373         /* Reset loop variables */
374         i = Element = 0;
375 
376         /* Start looping our address uage list and interrupts */
377         CurrentAddress = HalpAddressUsageList;
378         while (TRUE)
379         {
380             /* Check for valid vector number */
381             if (i <= MAXIMUM_IDTVECTOR)
382             {
383                 /* Check if this entry should be parsed */
384                 if ((HalpIDTUsageFlags[i].Flags & FlagMatch))
385                 {
386                     /* Parse it */
387                     HalpBuildPartialFromIdt(i, &RawPartial, &TranslatedPartial);
388                     i++;
389                 }
390                 else
391                 {
392                     /* Skip this entry */
393                     i++;
394                     continue;
395                 }
396             }
397             else
398             {
399                 /* This is an address instead */
400                 if (!CurrentAddress) break;
401 
402                 /* Check if the address should be reported */
403                 if (!(CurrentAddress->Flags & FlagMatch) ||
404                     !(CurrentAddress->Element[Element].Length))
405                 {
406                     /* Nope, skip it */
407                     Element = 0;
408                     CurrentAddress = CurrentAddress->Next;
409                     continue;
410                 }
411 
412                 /* Otherwise, parse the entry */
413                 HalpBuildPartialFromAddress(Interface,
414                                             CurrentAddress,
415                                             Element,
416                                             &RawPartial,
417                                             &TranslatedPartial);
418                 Element++;
419             }
420 
421             /* Check for interface change */
422             if (RawFull->InterfaceType != Interface)
423             {
424                 /* We need to add another full descriptor */
425                 RawList->Count++;
426                 TranslatedList->Count++;
427 
428                 /* The full descriptor follows wherever we were */
429                 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
430                 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
431 
432                 /* And it is of this new interface type */
433                 RawFull->InterfaceType = Interface;
434                 TranslatedFull->InterfaceType = Interface;
435 
436                 /* And its partial descriptors begin here */
437                 RawPartialList = &RawFull->PartialResourceList;
438                 TranslatedPartialList = &TranslatedFull->PartialResourceList;
439 
440                 /* And our next full descriptor should follow here */
441                 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
442                 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
443             }
444 
445             /* We have written a new partial descriptor */
446             RawPartialList->Count++;
447             TranslatedPartialList->Count++;
448 
449             /* Copy our local descriptors into the actual list */
450             RtlCopyMemory(CurrentRaw, &RawPartial, sizeof(RawPartial));
451             RtlCopyMemory(CurrentTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
452 
453             /* Move to the next partial descriptor */
454             CurrentRaw++;
455             CurrentTranslated++;
456         }
457     }
458 
459     /* Get the final list of the size for the kernel call later */
460     ListSize = (ULONG)((ULONG_PTR)CurrentRaw - (ULONG_PTR)RawList);
461 
462     /* Now reset back to the first full descriptor */
463     RawFull = RawList->List;
464     TranslatedFull = TranslatedList->List;
465 
466     /* And loop all the full descriptors */
467     for (i = 0; i < RawList->Count; i++)
468     {
469         /* Get the first partial descriptor in this list */
470         CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
471         CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
472 
473         /* Get the count of partials in this list */
474         Count = RawFull->PartialResourceList.Count;
475 
476         /* Loop all the partials in this list */
477         for (j = 0; j < Count; j++)
478         {
479             /* Get the sort value at this point */
480             HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
481 
482             /* Save the current sort pointer */
483             SortedRaw = CurrentRaw;
484             SortedTranslated = CurrentTranslated;
485 
486             /* Loop all descriptors starting from this one */
487             for (k = j; k < Count; k++)
488             {
489                 /* Get the sort value at the sort point */
490                 HalpGetResourceSortValue(SortedRaw, &SortScale, &SortValue);
491 
492                 /* Check if a swap needs to occur */
493                 if ((SortScale < CurrentScale) ||
494                     ((SortScale == CurrentScale) &&
495                      (SortValue.QuadPart <= CurrentSortValue.QuadPart)))
496                 {
497                     /* Swap raw partial with the sort location partial */
498                     RtlCopyMemory(&RawPartial, CurrentRaw, sizeof(RawPartial));
499                     RtlCopyMemory(CurrentRaw, SortedRaw, sizeof(RawPartial));
500                     RtlCopyMemory(SortedRaw, &RawPartial, sizeof(RawPartial));
501 
502                     /* Swap translated partial in the same way */
503                     RtlCopyMemory(&TranslatedPartial, CurrentTranslated, sizeof(TranslatedPartial));
504                     RtlCopyMemory(CurrentTranslated, SortedTranslated, sizeof(TranslatedPartial));
505                     RtlCopyMemory(SortedTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
506 
507                     /* Update the sort value at this point */
508                     HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
509                 }
510 
511                 /* The sort location has been updated */
512                 SortedRaw++;
513                 SortedTranslated++;
514             }
515 
516             /* Move to the next partial */
517             CurrentRaw++;
518             CurrentTranslated++;
519         }
520 
521         /* Move to the next full descriptor */
522         RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
523         TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
524     }
525 
526     /* Mark this is an ACPI system, if it is */
527     HalpMarkAcpiHal();
528 
529     /* Tell the kernel about all this */
530     IoReportHalResourceUsage(HalName,
531                              RawList,
532                              TranslatedList,
533                              ListSize);
534 
535     /* Free our lists */
536     ExFreePool(RawList);
537     ExFreePool(TranslatedList);
538 
539     /* Get the machine's serial number */
540     HalpReportSerialNumber();
541 }
542 #endif /* !_MINIHAL_ */
543 
544 CODE_SEG("INIT")
545 VOID
546 NTAPI
547 HalpRegisterVector(IN UCHAR Flags,
548                    IN ULONG BusVector,
549                    IN ULONG SystemVector,
550                    IN KIRQL Irql)
551 {
552     /* Save the vector flags */
553     HalpIDTUsageFlags[SystemVector].Flags = Flags;
554 
555     /* Save the vector data */
556     HalpIDTUsage[SystemVector].Irql  = Irql;
557     HalpIDTUsage[SystemVector].BusReleativeVector = (UCHAR)BusVector;
558 }
559 
560 #ifndef _MINIHAL_
561 CODE_SEG("INIT")
562 VOID
563 NTAPI
564 HalpEnableInterruptHandler(IN UCHAR Flags,
565                            IN ULONG BusVector,
566                            IN ULONG SystemVector,
567                            IN KIRQL Irql,
568                            IN PVOID Handler,
569                            IN KINTERRUPT_MODE Mode)
570 {
571     /* Set the IDT_LATCHED flag for latched interrupts */
572     if (Mode == Latched) Flags |= IDT_LATCHED;
573 
574     /* Register the vector */
575     HalpRegisterVector(Flags, BusVector, SystemVector, Irql);
576 
577     /* Connect the interrupt */
578     KeRegisterInterruptHandler(SystemVector, Handler);
579 
580     /* Enable the interrupt */
581     HalEnableSystemInterrupt(SystemVector, Irql, Mode);
582 }
583 
584 CODE_SEG("INIT")
585 VOID
586 NTAPI
587 HalpGetNMICrashFlag(VOID)
588 {
589     UNICODE_STRING ValueName;
590     UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
591     OBJECT_ATTRIBUTES ObjectAttributes;
592     ULONG ResultLength;
593     HANDLE Handle;
594     NTSTATUS Status;
595     KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
596 
597     /* Set default */
598     HalpNMIDumpFlag = 0;
599 
600     /* Initialize attributes */
601     InitializeObjectAttributes(&ObjectAttributes,
602                                &KeyName,
603                                OBJ_CASE_INSENSITIVE,
604                                NULL,
605                                NULL);
606 
607     /* Open crash key */
608     Status = ZwOpenKey(&Handle, KEY_READ, &ObjectAttributes);
609     if (NT_SUCCESS(Status))
610     {
611         /* Query key value */
612         RtlInitUnicodeString(&ValueName, L"NMICrashDump");
613         Status = ZwQueryValueKey(Handle,
614                                  &ValueName,
615                                  KeyValuePartialInformation,
616                                  &KeyValueInformation,
617                                  sizeof(KeyValueInformation),
618                                  &ResultLength);
619         if (NT_SUCCESS(Status))
620         {
621             /* Check for valid data */
622             if (ResultLength == sizeof(KEY_VALUE_PARTIAL_INFORMATION))
623             {
624                 /* Read the flag */
625                 HalpNMIDumpFlag = KeyValueInformation.Data[0];
626             }
627         }
628 
629         /* We're done */
630         ZwClose(Handle);
631     }
632 }
633 #endif  /* !_MINIHAL_ */
634 
635 /* EOF */
636