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 *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 BOOLEAN HalpGetInfoFromACPI
;
18 BOOLEAN HalpNMIDumpFlag
;
19 PUCHAR KdComPortInUse
;
20 PADDRESS_USAGE HalpAddressUsageList
;
21 IDTUsageFlags HalpIDTUsageFlags
[MAXIMUM_IDTVECTOR
];
22 IDTUsage HalpIDTUsage
[MAXIMUM_IDTVECTOR
];
24 USHORT HalpComPortIrqMapping
[5][2] =
33 ADDRESS_USAGE HalpComIoSpace
=
35 NULL
, CmResourceTypePort
, IDT_INTERNAL
,
37 {0x2F8, 0x8}, /* COM 1 */
42 ADDRESS_USAGE HalpDefaultIoSpace
=
44 NULL
, CmResourceTypePort
, IDT_INTERNAL
,
46 {0x2000, 0xC000}, /* Everything */
47 {0xC000, 0x1000}, /* DMA 2 */
48 {0x8000, 0x1000}, /* DMA 1 */
49 {0x2000, 0x200}, /* PIC 1 */
50 {0xA000, 0x200}, /* PIC 2 */
51 {0x4000, 0x400}, /* PIT 1 */
52 {0x4800, 0x400}, /* PIT 2 */
53 {0x9200, 0x100}, /* System Control Port A */
54 {0x7000, 0x200}, /* CMOS */
55 {0xF000, 0x1000}, /* x87 Coprocessor */
56 {0xCF800, 0x800}, /* PCI 0 */
61 /* FUNCTIONS ******************************************************************/
66 HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
,
68 OUT PLARGE_INTEGER Value
)
70 /* Sorting depends on resource type */
71 switch (Descriptor
->Type
)
73 case CmResourceTypeInterrupt
:
75 /* Interrupt goes by level */
77 *Value
= RtlConvertUlongToLargeInteger(Descriptor
->u
.Interrupt
.Level
);
80 case CmResourceTypePort
:
82 /* Port goes by port address */
84 *Value
= Descriptor
->u
.Port
.Start
;
87 case CmResourceTypeMemory
:
89 /* Memory goes by base address */
91 *Value
= Descriptor
->u
.Memory
.Start
;
98 *Value
= RtlConvertUlongToLargeInteger(0);
105 HalpBuildPartialFromIdt(IN ULONG Entry
,
106 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
107 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
)
109 /* Exclusive interrupt entry */
110 RawDescriptor
->Type
= CmResourceTypeInterrupt
;
111 RawDescriptor
->ShareDisposition
= CmResourceShareDriverExclusive
;
113 /* Check the interrupt type */
114 if (HalpIDTUsageFlags
[Entry
].Flags
& IDT_LATCHED
)
117 RawDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
122 RawDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
125 /* Get vector and level from IDT usage */
126 RawDescriptor
->u
.Interrupt
.Vector
= HalpIDTUsage
[Entry
].BusReleativeVector
;
127 RawDescriptor
->u
.Interrupt
.Level
= HalpIDTUsage
[Entry
].BusReleativeVector
;
129 /* Affinity is all the CPUs */
130 RawDescriptor
->u
.Interrupt
.Affinity
= HalpActiveProcessors
;
132 /* The translated copy is identical */
133 RtlCopyMemory(TranslatedDescriptor
, RawDescriptor
, sizeof(TranslatedDescriptor
));
135 /* But the vector and IRQL must be set correctly */
136 TranslatedDescriptor
->u
.Interrupt
.Vector
= Entry
;
137 TranslatedDescriptor
->u
.Interrupt
.Level
= HalpIDTUsage
[Entry
].Irql
;
142 HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface
,
143 IN PADDRESS_USAGE CurrentAddress
,
145 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
146 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
)
150 /* Set the type and make it exclusive */
151 RawDescriptor
->Type
= CurrentAddress
->Type
;
152 RawDescriptor
->ShareDisposition
= CmResourceShareDriverExclusive
;
154 /* Check what this is */
155 if (RawDescriptor
->Type
== CmResourceTypePort
)
157 /* Write out port data */
159 RawDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
160 RawDescriptor
->u
.Port
.Start
.HighPart
= 0;
161 RawDescriptor
->u
.Port
.Start
.LowPart
= CurrentAddress
->Element
[Element
].Start
;
162 RawDescriptor
->u
.Port
.Length
= CurrentAddress
->Element
[Element
].Length
;
164 /* Determine if 16-bit port addresses are allowed */
165 RawDescriptor
->Flags
|= HalpIs16BitPortDecodeSupported();
169 /* Write out memory data */
171 RawDescriptor
->Flags
= (CurrentAddress
->Flags
& IDT_READ_ONLY
) ?
172 CM_RESOURCE_MEMORY_READ_ONLY
:
173 CM_RESOURCE_MEMORY_READ_WRITE
;
174 RawDescriptor
->u
.Memory
.Start
.HighPart
= 0;
175 RawDescriptor
->u
.Memory
.Start
.LowPart
= CurrentAddress
->Element
[Element
].Start
;
176 RawDescriptor
->u
.Memory
.Length
= CurrentAddress
->Element
[Element
].Length
;
179 /* Make an identical copy to begin with */
180 RtlCopyMemory(TranslatedDescriptor
, RawDescriptor
, sizeof(TranslatedDescriptor
));
182 /* Check what this is */
183 if (RawDescriptor
->Type
== CmResourceTypePort
)
185 /* Translate the port */
186 HalTranslateBusAddress(Interface
,
188 RawDescriptor
->u
.Port
.Start
,
190 &TranslatedDescriptor
->u
.Port
.Start
);
192 /* If it turns out this is memory once translated, flag it */
193 if (AddressSpace
== 0) TranslatedDescriptor
->Flags
= CM_RESOURCE_PORT_MEMORY
;
198 /* Translate the memory */
199 HalTranslateBusAddress(Interface
,
201 RawDescriptor
->u
.Memory
.Start
,
203 &TranslatedDescriptor
->u
.Memory
.Start
);
209 HalpReportResourceUsage(IN PUNICODE_STRING HalName
,
210 IN INTERFACE_TYPE InterfaceType
)
212 PCM_RESOURCE_LIST RawList
, TranslatedList
;
213 PCM_FULL_RESOURCE_DESCRIPTOR RawFull
, TranslatedFull
;
214 PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw
, CurrentTranslated
, SortedRaw
, SortedTranslated
;
215 CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial
, TranslatedPartial
;
216 PCM_PARTIAL_RESOURCE_LIST RawPartialList
= NULL
, TranslatedPartialList
= NULL
;
217 INTERFACE_TYPE Interface
;
218 ULONG i
, j
, k
, ListSize
, Count
, Port
, Element
, CurrentScale
, SortScale
, ReportType
, FlagMatch
;
219 ADDRESS_USAGE
*CurrentAddress
;
220 LARGE_INTEGER CurrentSortValue
, SortValue
;
221 DbgPrint("%wZ Detected\n", HalName
);
223 /* Check if KD is using a COM port */
226 /* Enter it into the I/O space */
227 HalpComIoSpace
.Element
[0].Start
= (ULONG_PTR
)KdComPortInUse
;
228 HalpComIoSpace
.Next
= HalpAddressUsageList
;
229 HalpAddressUsageList
= &HalpComIoSpace
;
231 /* Use the debug port table if we have one */
232 HalpGetInfoFromACPI
= HalpGetDebugPortTable();
234 /* Check if we're using ACPI */
235 if (!HalpGetInfoFromACPI
)
237 /* No, so use our local table */
238 Port
= HalpComPortIrqMapping
[0][0];
239 for (i
= 0; Port
; i
++)
241 /* Is this the port we want? */
242 if (Port
== (ULONG_PTR
)KdComPortInUse
)
245 HalpRegisterVector(IDT_DEVICE
| IDT_LATCHED
,
246 HalpComPortIrqMapping
[i
][1],
247 HalpComPortIrqMapping
[i
][1] +
253 Port
= HalpComPortIrqMapping
[i
][0];
258 /* On non-ACPI systems, we need to build an address map */
259 HalpBuildAddressMap();
261 /* Allocate the master raw and translated lists */
262 RawList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, ' laH');
263 TranslatedList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, ' laH');
264 if (!(RawList
) || !(TranslatedList
))
266 /* Bugcheck the system */
267 KeBugCheckEx(HAL_MEMORY_ALLOCATION
,
274 /* Zero out the lists */
275 RtlZeroMemory(RawList
, PAGE_SIZE
* 2);
276 RtlZeroMemory(TranslatedList
, PAGE_SIZE
* 2);
278 /* Set the interface type to begin with */
279 RawList
->List
[0].InterfaceType
= InterfaceTypeUndefined
;
281 /* Loop all IDT entries that are not IRQs */
282 for (i
= 0; i
< PRIMARY_VECTOR_BASE
; i
++)
284 /* Check if the IDT isn't owned */
285 if (!(HalpIDTUsageFlags
[i
].Flags
& IDT_REGISTERED
))
287 /* Then register it for internal usage */
288 HalpIDTUsageFlags
[i
].Flags
= IDT_INTERNAL
;
289 HalpIDTUsage
[i
].BusReleativeVector
= i
;
293 /* Our full raw descriptors start here */
294 RawFull
= RawList
->List
;
296 /* Keep track of the current partial raw and translated descriptors */
297 CurrentRaw
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)RawList
->List
;
298 CurrentTranslated
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)TranslatedList
->List
;
301 for (ReportType
= 0; ReportType
< 2; ReportType
++)
303 /* Pass 0 is for device usage */
306 FlagMatch
= IDT_DEVICE
& ~IDT_REGISTERED
;
307 Interface
= InterfaceType
;
311 /* Past 1 is for internal HAL usage */
312 FlagMatch
= IDT_INTERNAL
& ~IDT_REGISTERED
;
313 Interface
= Internal
;
316 /* Reset loop variables */
319 /* Start looping our address uage list and interrupts */
320 CurrentAddress
= HalpAddressUsageList
;
323 /* Check for valid vector number */
324 if (i
<= MAXIMUM_IDTVECTOR
)
326 /* Check if this entry should be parsed */
327 if ((HalpIDTUsageFlags
[i
].Flags
& FlagMatch
))
330 HalpBuildPartialFromIdt(i
, &RawPartial
, &TranslatedPartial
);
335 /* Skip this entry */
342 /* This is an address instead */
343 if (!CurrentAddress
) break;
345 /* Check if the address should be reported */
346 if (!(CurrentAddress
->Flags
& FlagMatch
) ||
347 !(CurrentAddress
->Element
[Element
].Length
))
351 CurrentAddress
= CurrentAddress
->Next
;
355 /* Otherwise, parse the entry */
356 HalpBuildPartialFromAddress(Interface
,
364 /* Check for interface change */
365 if (RawFull
->InterfaceType
!= Interface
)
367 /* We need to add another full descriptor */
369 TranslatedList
->Count
++;
371 /* The full descriptor follows wherever we were */
372 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
373 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
375 /* And it is of this new interface type */
376 RawFull
->InterfaceType
= Interface
;
377 TranslatedFull
->InterfaceType
= Interface
;
379 /* And its partial descriptors begin here */
380 RawPartialList
= &RawFull
->PartialResourceList
;
381 TranslatedPartialList
= &TranslatedFull
->PartialResourceList
;
383 /* And our next full descriptor should follow here */
384 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
385 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
388 /* We have written a new partial descriptor */
389 RawPartialList
->Count
++;
390 TranslatedPartialList
->Count
++;
392 /* Copy our local descriptors into the actual list */
393 RtlCopyMemory(CurrentRaw
, &RawPartial
, sizeof(RawPartial
));
394 RtlCopyMemory(CurrentTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
396 /* Move to the next partial descriptor */
402 /* Get the final list of the size for the kernel call later */
403 ListSize
= (ULONG_PTR
)CurrentRaw
- (ULONG_PTR
)RawList
;
405 /* Now reset back to the first full descriptor */
406 RawFull
= RawList
->List
;
407 TranslatedFull
= TranslatedList
->List
;
409 /* And loop all the full descriptors */
410 for (i
= 0; i
< RawList
->Count
; i
++)
412 /* Get the first partial descriptor in this list */
413 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
414 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
416 /* Get the count of partials in this list */
417 Count
= RawFull
->PartialResourceList
.Count
;
419 /* Loop all the partials in this list */
420 for (j
= 0; j
< Count
; j
++)
422 /* Get the sort value at this point */
423 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
425 /* Save the current sort pointer */
426 SortedRaw
= CurrentRaw
;
427 SortedTranslated
= CurrentTranslated
;
429 /* Loop all descriptors starting from this one */
430 for (k
= j
; k
< Count
; k
++)
432 /* Get the sort value at the sort point */
433 HalpGetResourceSortValue(SortedRaw
, &SortScale
, &SortValue
);
435 /* Check if a swap needs to occur */
436 if ((SortScale
< CurrentScale
) ||
437 ((SortScale
== CurrentScale
) &&
438 (SortValue
.QuadPart
<= CurrentSortValue
.QuadPart
)))
440 /* Swap raw partial with the sort location partial */
441 RtlCopyMemory(&RawPartial
, CurrentRaw
, sizeof(RawPartial
));
442 RtlCopyMemory(CurrentRaw
, SortedRaw
, sizeof(RawPartial
));
443 RtlCopyMemory(SortedRaw
, &RawPartial
, sizeof(RawPartial
));
445 /* Swap translated partial in the same way */
446 RtlCopyMemory(&TranslatedPartial
, CurrentTranslated
, sizeof(TranslatedPartial
));
447 RtlCopyMemory(CurrentTranslated
, SortedTranslated
, sizeof(TranslatedPartial
));
448 RtlCopyMemory(SortedTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
450 /* Update the sort value at this point */
451 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
454 /* The sort location has been updated */
459 /* Move to the next partial */
464 /* Move to the next full descriptor */
465 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
466 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
469 /* Mark this is an ACPI system, if it is */
472 /* Tell the kernel about all this */
473 IoReportHalResourceUsage(HalName
,
480 ExFreePool(TranslatedList
);
482 /* Get the machine's serial number */
483 HalpReportSerialNumber();
489 HalpRegisterVector(IN UCHAR Flags
,
491 IN ULONG SystemVector
,
494 /* Save the vector flags */
495 HalpIDTUsageFlags
[SystemVector
].Flags
= Flags
;
497 /* Save the vector data */
498 HalpIDTUsage
[SystemVector
].Irql
= Irql
;
499 HalpIDTUsage
[SystemVector
].BusReleativeVector
= BusVector
;
505 HalpEnableInterruptHandler(IN UCHAR Flags
,
507 IN ULONG SystemVector
,
510 IN KINTERRUPT_MODE Mode
)
512 /* Register the vector */
513 HalpRegisterVector(Flags
, BusVector
, SystemVector
, Irql
);
515 /* Connect the interrupt */
516 KeRegisterInterruptHandler(SystemVector
, Handler
);
518 /* Enable the interrupt */
519 HalEnableSystemInterrupt(SystemVector
, Irql
, Mode
);
524 HalpGetNMICrashFlag(VOID
)
526 UNICODE_STRING ValueName
;
527 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
528 OBJECT_ATTRIBUTES ObjectAttributes
;
532 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
537 /* Initialize attributes */
538 InitializeObjectAttributes(&ObjectAttributes
,
540 OBJ_CASE_INSENSITIVE
,
545 Status
= ZwOpenKey(&Handle
, KEY_READ
, &ObjectAttributes
);
546 if (NT_SUCCESS(Status
))
548 /* Query key value */
549 RtlInitUnicodeString(&ValueName
, L
"NMICrashDump");
550 Status
= ZwQueryValueKey(Handle
,
552 KeyValuePartialInformation
,
553 &KeyValueInformation
,
554 sizeof(KeyValueInformation
),
556 if (NT_SUCCESS(Status
))
558 /* Check for valid data */
559 if (ResultLength
== sizeof(KEY_VALUE_PARTIAL_INFORMATION
))
562 HalpNMIDumpFlag
= KeyValueInformation
.Data
[0];