3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/usage.c
5 * PURPOSE: HAL Resource Report Routines
6 * PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org)
9 /* INCLUDES *******************************************************************/
17 HalpGetResourceSortValue(
18 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
,
20 OUT PLARGE_INTEGER Value
25 HalpBuildPartialFromIdt(
27 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
28 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
33 HalpBuildPartialFromAddress(
34 IN INTERFACE_TYPE Interface
,
35 IN PADDRESS_USAGE CurrentAddress
,
37 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
38 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
41 #if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_)
42 #pragma alloc_text(INIT, HalpBuildPartialFromAddress)
43 #pragma alloc_text(INIT, HalpBuildPartialFromIdt)
44 #pragma alloc_text(INIT, HalpEnableInterruptHandler)
45 #pragma alloc_text(INIT, HalpGetNMICrashFlag)
46 #pragma alloc_text(INIT, HalpGetResourceSortValue)
47 #pragma alloc_text(INIT, HalpRegisterVector)
48 #pragma alloc_text(INIT, HalpReportResourceUsage)
51 /* GLOBALS ********************************************************************/
53 BOOLEAN HalpGetInfoFromACPI
;
54 BOOLEAN HalpNMIDumpFlag
;
55 PUCHAR KdComPortInUse
;
56 PADDRESS_USAGE HalpAddressUsageList
;
57 IDTUsageFlags HalpIDTUsageFlags
[MAXIMUM_IDTVECTOR
+1];
58 IDTUsage HalpIDTUsage
[MAXIMUM_IDTVECTOR
+1];
60 USHORT HalpComPortIrqMapping
[5][2] =
69 ADDRESS_USAGE HalpComIoSpace
=
71 NULL
, CmResourceTypePort
, IDT_INTERNAL
,
73 {0x2F8, 0x8}, /* COM 1 */
78 ADDRESS_USAGE HalpDefaultIoSpace
=
80 NULL
, CmResourceTypePort
, IDT_INTERNAL
,
82 {0x00, 0x20}, /* DMA 1 */
83 {0xC0, 0x20}, /* DMA 2 */
84 {0x80, 0x10}, /* DMA EPAR */
85 {0x20, 0x2}, /* PIC 1 */
86 {0xA0, 0x2}, /* PIC 2 */
87 {0x40, 0x4}, /* PIT 1 */
88 {0x48, 0x4}, /* PIT 2 */
89 {0x92, 0x1}, /* System Control Port A */
90 {0x70, 0x2}, /* CMOS */
91 {0xF0, 0x10}, /* x87 Coprocessor */
92 {0xCF8, 0x8}, /* PCI 0 */
97 /* FUNCTIONS ******************************************************************/
103 HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
,
105 OUT PLARGE_INTEGER Value
)
107 /* Sorting depends on resource type */
108 switch (Descriptor
->Type
)
110 case CmResourceTypeInterrupt
:
112 /* Interrupt goes by level */
114 *Value
= RtlConvertUlongToLargeInteger(Descriptor
->u
.Interrupt
.Level
);
117 case CmResourceTypePort
:
119 /* Port goes by port address */
121 *Value
= Descriptor
->u
.Port
.Start
;
124 case CmResourceTypeMemory
:
126 /* Memory goes by base address */
128 *Value
= Descriptor
->u
.Memory
.Start
;
135 *Value
= RtlConvertUlongToLargeInteger(0);
143 HalpBuildPartialFromIdt(IN ULONG Entry
,
144 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
145 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
)
147 /* Exclusive interrupt entry */
148 RawDescriptor
->Type
= CmResourceTypeInterrupt
;
149 RawDescriptor
->ShareDisposition
= CmResourceShareDriverExclusive
;
151 /* Check the interrupt type */
152 if (HalpIDTUsageFlags
[Entry
].Flags
& IDT_LATCHED
)
155 RawDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
160 RawDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
163 /* Get vector and level from IDT usage */
164 RawDescriptor
->u
.Interrupt
.Vector
= HalpIDTUsage
[Entry
].BusReleativeVector
;
165 RawDescriptor
->u
.Interrupt
.Level
= HalpIDTUsage
[Entry
].BusReleativeVector
;
167 /* Affinity is all the CPUs */
168 RawDescriptor
->u
.Interrupt
.Affinity
= HalpActiveProcessors
;
170 /* The translated copy is identical */
171 RtlCopyMemory(TranslatedDescriptor
, RawDescriptor
, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
173 /* But the vector and IRQL must be set correctly */
174 TranslatedDescriptor
->u
.Interrupt
.Vector
= Entry
;
175 TranslatedDescriptor
->u
.Interrupt
.Level
= HalpIDTUsage
[Entry
].Irql
;
181 HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface
,
182 IN PADDRESS_USAGE CurrentAddress
,
184 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
185 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
)
189 /* Set the type and make it exclusive */
190 RawDescriptor
->Type
= CurrentAddress
->Type
;
191 RawDescriptor
->ShareDisposition
= CmResourceShareDriverExclusive
;
193 /* Check what this is */
194 if (RawDescriptor
->Type
== CmResourceTypePort
)
196 /* Write out port data */
198 RawDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
199 RawDescriptor
->u
.Port
.Start
.HighPart
= 0;
200 RawDescriptor
->u
.Port
.Start
.LowPart
= CurrentAddress
->Element
[Element
].Start
;
201 RawDescriptor
->u
.Port
.Length
= CurrentAddress
->Element
[Element
].Length
;
203 /* Determine if 16-bit port addresses are allowed */
204 RawDescriptor
->Flags
|= HalpIs16BitPortDecodeSupported();
208 /* Write out memory data */
210 RawDescriptor
->Flags
= (CurrentAddress
->Flags
& IDT_READ_ONLY
) ?
211 CM_RESOURCE_MEMORY_READ_ONLY
:
212 CM_RESOURCE_MEMORY_READ_WRITE
;
213 RawDescriptor
->u
.Memory
.Start
.HighPart
= 0;
214 RawDescriptor
->u
.Memory
.Start
.LowPart
= CurrentAddress
->Element
[Element
].Start
;
215 RawDescriptor
->u
.Memory
.Length
= CurrentAddress
->Element
[Element
].Length
;
218 /* Make an identical copy to begin with */
219 RtlCopyMemory(TranslatedDescriptor
, RawDescriptor
, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
221 /* Check what this is */
222 if (RawDescriptor
->Type
== CmResourceTypePort
)
224 /* Translate the port */
225 HalTranslateBusAddress(Interface
,
227 RawDescriptor
->u
.Port
.Start
,
229 &TranslatedDescriptor
->u
.Port
.Start
);
231 /* If it turns out this is memory once translated, flag it */
232 if (AddressSpace
== 0) TranslatedDescriptor
->Flags
= CM_RESOURCE_PORT_MEMORY
;
237 /* Translate the memory */
238 HalTranslateBusAddress(Interface
,
240 RawDescriptor
->u
.Memory
.Start
,
242 &TranslatedDescriptor
->u
.Memory
.Start
);
249 HalpReportResourceUsage(IN PUNICODE_STRING HalName
,
250 IN INTERFACE_TYPE InterfaceType
)
252 PCM_RESOURCE_LIST RawList
, TranslatedList
;
253 PCM_FULL_RESOURCE_DESCRIPTOR RawFull
, TranslatedFull
;
254 PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw
, CurrentTranslated
, SortedRaw
, SortedTranslated
;
255 CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial
, TranslatedPartial
;
256 PCM_PARTIAL_RESOURCE_LIST RawPartialList
= NULL
, TranslatedPartialList
= NULL
;
257 INTERFACE_TYPE Interface
;
258 ULONG i
, j
, k
, ListSize
, Count
, Port
, Element
, CurrentScale
, SortScale
, ReportType
, FlagMatch
;
259 ADDRESS_USAGE
*CurrentAddress
;
260 LARGE_INTEGER CurrentSortValue
, SortValue
;
261 DbgPrint("%wZ Detected\n", HalName
);
263 /* Check if KD is using a COM port */
266 /* Enter it into the I/O space */
267 HalpComIoSpace
.Element
[0].Start
= PtrToUlong(KdComPortInUse
);
268 HalpComIoSpace
.Next
= HalpAddressUsageList
;
269 HalpAddressUsageList
= &HalpComIoSpace
;
271 /* Use the debug port table if we have one */
272 HalpGetInfoFromACPI
= HalpGetDebugPortTable();
274 /* Check if we're using ACPI */
275 if (!HalpGetInfoFromACPI
)
277 /* No, so use our local table */
278 for (i
= 0, Port
= HalpComPortIrqMapping
[i
][0];
280 i
++, Port
= HalpComPortIrqMapping
[i
][0])
282 /* Is this the port we want? */
283 if (Port
== (ULONG_PTR
)KdComPortInUse
)
286 HalpRegisterVector(IDT_DEVICE
| IDT_LATCHED
,
287 HalpComPortIrqMapping
[i
][1],
288 HalpComPortIrqMapping
[i
][1] +
296 /* On non-ACPI systems, we need to build an address map */
297 HalpBuildAddressMap();
299 /* Allocate the master raw and translated lists */
300 RawList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, TAG_HAL
);
301 TranslatedList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, TAG_HAL
);
302 if (!(RawList
) || !(TranslatedList
))
304 /* Bugcheck the system */
305 KeBugCheckEx(HAL_MEMORY_ALLOCATION
,
312 /* Zero out the lists */
313 RtlZeroMemory(RawList
, PAGE_SIZE
* 2);
314 RtlZeroMemory(TranslatedList
, PAGE_SIZE
* 2);
316 /* Set the interface type to begin with */
317 RawList
->List
[0].InterfaceType
= InterfaceTypeUndefined
;
319 /* Loop all IDT entries that are not IRQs */
320 for (i
= 0; i
< PRIMARY_VECTOR_BASE
; i
++)
322 /* Check if the IDT isn't owned */
323 if (!(HalpIDTUsageFlags
[i
].Flags
& IDT_REGISTERED
))
325 /* Then register it for internal usage */
326 HalpIDTUsageFlags
[i
].Flags
= IDT_INTERNAL
;
327 HalpIDTUsage
[i
].BusReleativeVector
= (UCHAR
)i
;
331 /* Our full raw descriptors start here */
332 RawFull
= RawList
->List
;
334 /* Keep track of the current partial raw and translated descriptors */
335 CurrentRaw
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)RawList
->List
;
336 CurrentTranslated
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)TranslatedList
->List
;
339 for (ReportType
= 0; ReportType
< 2; ReportType
++)
341 /* Pass 0 is for device usage */
344 FlagMatch
= IDT_DEVICE
& ~IDT_REGISTERED
;
345 Interface
= InterfaceType
;
349 /* Past 1 is for internal HAL usage */
350 FlagMatch
= IDT_INTERNAL
& ~IDT_REGISTERED
;
351 Interface
= Internal
;
354 /* Reset loop variables */
357 /* Start looping our address uage list and interrupts */
358 CurrentAddress
= HalpAddressUsageList
;
361 /* Check for valid vector number */
362 if (i
<= MAXIMUM_IDTVECTOR
)
364 /* Check if this entry should be parsed */
365 if ((HalpIDTUsageFlags
[i
].Flags
& FlagMatch
))
368 HalpBuildPartialFromIdt(i
, &RawPartial
, &TranslatedPartial
);
373 /* Skip this entry */
380 /* This is an address instead */
381 if (!CurrentAddress
) break;
383 /* Check if the address should be reported */
384 if (!(CurrentAddress
->Flags
& FlagMatch
) ||
385 !(CurrentAddress
->Element
[Element
].Length
))
389 CurrentAddress
= CurrentAddress
->Next
;
393 /* Otherwise, parse the entry */
394 HalpBuildPartialFromAddress(Interface
,
402 /* Check for interface change */
403 if (RawFull
->InterfaceType
!= Interface
)
405 /* We need to add another full descriptor */
407 TranslatedList
->Count
++;
409 /* The full descriptor follows wherever we were */
410 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
411 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
413 /* And it is of this new interface type */
414 RawFull
->InterfaceType
= Interface
;
415 TranslatedFull
->InterfaceType
= Interface
;
417 /* And its partial descriptors begin here */
418 RawPartialList
= &RawFull
->PartialResourceList
;
419 TranslatedPartialList
= &TranslatedFull
->PartialResourceList
;
421 /* And our next full descriptor should follow here */
422 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
423 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
426 /* We have written a new partial descriptor */
427 RawPartialList
->Count
++;
428 TranslatedPartialList
->Count
++;
430 /* Copy our local descriptors into the actual list */
431 RtlCopyMemory(CurrentRaw
, &RawPartial
, sizeof(RawPartial
));
432 RtlCopyMemory(CurrentTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
434 /* Move to the next partial descriptor */
440 /* Get the final list of the size for the kernel call later */
441 ListSize
= (ULONG
)((ULONG_PTR
)CurrentRaw
- (ULONG_PTR
)RawList
);
443 /* Now reset back to the first full descriptor */
444 RawFull
= RawList
->List
;
445 TranslatedFull
= TranslatedList
->List
;
447 /* And loop all the full descriptors */
448 for (i
= 0; i
< RawList
->Count
; i
++)
450 /* Get the first partial descriptor in this list */
451 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
452 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
454 /* Get the count of partials in this list */
455 Count
= RawFull
->PartialResourceList
.Count
;
457 /* Loop all the partials in this list */
458 for (j
= 0; j
< Count
; j
++)
460 /* Get the sort value at this point */
461 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
463 /* Save the current sort pointer */
464 SortedRaw
= CurrentRaw
;
465 SortedTranslated
= CurrentTranslated
;
467 /* Loop all descriptors starting from this one */
468 for (k
= j
; k
< Count
; k
++)
470 /* Get the sort value at the sort point */
471 HalpGetResourceSortValue(SortedRaw
, &SortScale
, &SortValue
);
473 /* Check if a swap needs to occur */
474 if ((SortScale
< CurrentScale
) ||
475 ((SortScale
== CurrentScale
) &&
476 (SortValue
.QuadPart
<= CurrentSortValue
.QuadPart
)))
478 /* Swap raw partial with the sort location partial */
479 RtlCopyMemory(&RawPartial
, CurrentRaw
, sizeof(RawPartial
));
480 RtlCopyMemory(CurrentRaw
, SortedRaw
, sizeof(RawPartial
));
481 RtlCopyMemory(SortedRaw
, &RawPartial
, sizeof(RawPartial
));
483 /* Swap translated partial in the same way */
484 RtlCopyMemory(&TranslatedPartial
, CurrentTranslated
, sizeof(TranslatedPartial
));
485 RtlCopyMemory(CurrentTranslated
, SortedTranslated
, sizeof(TranslatedPartial
));
486 RtlCopyMemory(SortedTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
488 /* Update the sort value at this point */
489 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
492 /* The sort location has been updated */
497 /* Move to the next partial */
502 /* Move to the next full descriptor */
503 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
504 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
507 /* Mark this is an ACPI system, if it is */
510 /* Tell the kernel about all this */
511 IoReportHalResourceUsage(HalName
,
518 ExFreePool(TranslatedList
);
520 /* Get the machine's serial number */
521 HalpReportSerialNumber();
528 HalpRegisterVector(IN UCHAR Flags
,
530 IN ULONG SystemVector
,
533 /* Save the vector flags */
534 HalpIDTUsageFlags
[SystemVector
].Flags
= Flags
;
536 /* Save the vector data */
537 HalpIDTUsage
[SystemVector
].Irql
= Irql
;
538 HalpIDTUsage
[SystemVector
].BusReleativeVector
= (UCHAR
)BusVector
;
545 HalpEnableInterruptHandler(IN UCHAR Flags
,
547 IN ULONG SystemVector
,
550 IN KINTERRUPT_MODE Mode
)
552 /* Set the IDT_LATCHED flag for latched interrupts */
553 if (Mode
== Latched
) Flags
|= IDT_LATCHED
;
555 /* Register the vector */
556 HalpRegisterVector(Flags
, BusVector
, SystemVector
, Irql
);
558 /* Connect the interrupt */
559 KeRegisterInterruptHandler(SystemVector
, Handler
);
561 /* Enable the interrupt */
562 HalEnableSystemInterrupt(SystemVector
, Irql
, Mode
);
568 HalpGetNMICrashFlag(VOID
)
570 UNICODE_STRING ValueName
;
571 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
572 OBJECT_ATTRIBUTES ObjectAttributes
;
576 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
581 /* Initialize attributes */
582 InitializeObjectAttributes(&ObjectAttributes
,
584 OBJ_CASE_INSENSITIVE
,
589 Status
= ZwOpenKey(&Handle
, KEY_READ
, &ObjectAttributes
);
590 if (NT_SUCCESS(Status
))
592 /* Query key value */
593 RtlInitUnicodeString(&ValueName
, L
"NMICrashDump");
594 Status
= ZwQueryValueKey(Handle
,
596 KeyValuePartialInformation
,
597 &KeyValueInformation
,
598 sizeof(KeyValueInformation
),
600 if (NT_SUCCESS(Status
))
602 /* Check for valid data */
603 if (ResultLength
== sizeof(KEY_VALUE_PARTIAL_INFORMATION
))
606 HalpNMIDumpFlag
= KeyValueInformation
.Data
[0];