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 for (i
= 0, Port
= HalpComPortIrqMapping
[i
][0];
240 i
++, Port
= HalpComPortIrqMapping
[i
][0])
242 /* Is this the port we want? */
243 if (Port
== (ULONG_PTR
)KdComPortInUse
)
246 HalpRegisterVector(IDT_DEVICE
| IDT_LATCHED
,
247 HalpComPortIrqMapping
[i
][1],
248 HalpComPortIrqMapping
[i
][1] +
256 /* On non-ACPI systems, we need to build an address map */
257 HalpBuildAddressMap();
259 /* Allocate the master raw and translated lists */
260 RawList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, ' laH');
261 TranslatedList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, ' laH');
262 if (!(RawList
) || !(TranslatedList
))
264 /* Bugcheck the system */
265 KeBugCheckEx(HAL_MEMORY_ALLOCATION
,
272 /* Zero out the lists */
273 RtlZeroMemory(RawList
, PAGE_SIZE
* 2);
274 RtlZeroMemory(TranslatedList
, PAGE_SIZE
* 2);
276 /* Set the interface type to begin with */
277 RawList
->List
[0].InterfaceType
= InterfaceTypeUndefined
;
279 /* Loop all IDT entries that are not IRQs */
280 for (i
= 0; i
< PRIMARY_VECTOR_BASE
; i
++)
282 /* Check if the IDT isn't owned */
283 if (!(HalpIDTUsageFlags
[i
].Flags
& IDT_REGISTERED
))
285 /* Then register it for internal usage */
286 HalpIDTUsageFlags
[i
].Flags
= IDT_INTERNAL
;
287 HalpIDTUsage
[i
].BusReleativeVector
= i
;
291 /* Our full raw descriptors start here */
292 RawFull
= RawList
->List
;
294 /* Keep track of the current partial raw and translated descriptors */
295 CurrentRaw
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)RawList
->List
;
296 CurrentTranslated
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)TranslatedList
->List
;
299 for (ReportType
= 0; ReportType
< 2; ReportType
++)
301 /* Pass 0 is for device usage */
304 FlagMatch
= IDT_DEVICE
& ~IDT_REGISTERED
;
305 Interface
= InterfaceType
;
309 /* Past 1 is for internal HAL usage */
310 FlagMatch
= IDT_INTERNAL
& ~IDT_REGISTERED
;
311 Interface
= Internal
;
314 /* Reset loop variables */
317 /* Start looping our address uage list and interrupts */
318 CurrentAddress
= HalpAddressUsageList
;
321 /* Check for valid vector number */
322 if (i
<= MAXIMUM_IDTVECTOR
)
324 /* Check if this entry should be parsed */
325 if ((HalpIDTUsageFlags
[i
].Flags
& FlagMatch
))
328 HalpBuildPartialFromIdt(i
, &RawPartial
, &TranslatedPartial
);
333 /* Skip this entry */
340 /* This is an address instead */
341 if (!CurrentAddress
) break;
343 /* Check if the address should be reported */
344 if (!(CurrentAddress
->Flags
& FlagMatch
) ||
345 !(CurrentAddress
->Element
[Element
].Length
))
349 CurrentAddress
= CurrentAddress
->Next
;
353 /* Otherwise, parse the entry */
354 HalpBuildPartialFromAddress(Interface
,
362 /* Check for interface change */
363 if (RawFull
->InterfaceType
!= Interface
)
365 /* We need to add another full descriptor */
367 TranslatedList
->Count
++;
369 /* The full descriptor follows wherever we were */
370 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
371 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
373 /* And it is of this new interface type */
374 RawFull
->InterfaceType
= Interface
;
375 TranslatedFull
->InterfaceType
= Interface
;
377 /* And its partial descriptors begin here */
378 RawPartialList
= &RawFull
->PartialResourceList
;
379 TranslatedPartialList
= &TranslatedFull
->PartialResourceList
;
381 /* And our next full descriptor should follow here */
382 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
383 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
386 /* We have written a new partial descriptor */
387 RawPartialList
->Count
++;
388 TranslatedPartialList
->Count
++;
390 /* Copy our local descriptors into the actual list */
391 RtlCopyMemory(CurrentRaw
, &RawPartial
, sizeof(RawPartial
));
392 RtlCopyMemory(CurrentTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
394 /* Move to the next partial descriptor */
400 /* Get the final list of the size for the kernel call later */
401 ListSize
= (ULONG_PTR
)CurrentRaw
- (ULONG_PTR
)RawList
;
403 /* Now reset back to the first full descriptor */
404 RawFull
= RawList
->List
;
405 TranslatedFull
= TranslatedList
->List
;
407 /* And loop all the full descriptors */
408 for (i
= 0; i
< RawList
->Count
; i
++)
410 /* Get the first partial descriptor in this list */
411 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
412 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
414 /* Get the count of partials in this list */
415 Count
= RawFull
->PartialResourceList
.Count
;
417 /* Loop all the partials in this list */
418 for (j
= 0; j
< Count
; j
++)
420 /* Get the sort value at this point */
421 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
423 /* Save the current sort pointer */
424 SortedRaw
= CurrentRaw
;
425 SortedTranslated
= CurrentTranslated
;
427 /* Loop all descriptors starting from this one */
428 for (k
= j
; k
< Count
; k
++)
430 /* Get the sort value at the sort point */
431 HalpGetResourceSortValue(SortedRaw
, &SortScale
, &SortValue
);
433 /* Check if a swap needs to occur */
434 if ((SortScale
< CurrentScale
) ||
435 ((SortScale
== CurrentScale
) &&
436 (SortValue
.QuadPart
<= CurrentSortValue
.QuadPart
)))
438 /* Swap raw partial with the sort location partial */
439 RtlCopyMemory(&RawPartial
, CurrentRaw
, sizeof(RawPartial
));
440 RtlCopyMemory(CurrentRaw
, SortedRaw
, sizeof(RawPartial
));
441 RtlCopyMemory(SortedRaw
, &RawPartial
, sizeof(RawPartial
));
443 /* Swap translated partial in the same way */
444 RtlCopyMemory(&TranslatedPartial
, CurrentTranslated
, sizeof(TranslatedPartial
));
445 RtlCopyMemory(CurrentTranslated
, SortedTranslated
, sizeof(TranslatedPartial
));
446 RtlCopyMemory(SortedTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
448 /* Update the sort value at this point */
449 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
452 /* The sort location has been updated */
457 /* Move to the next partial */
462 /* Move to the next full descriptor */
463 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
464 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
467 /* Mark this is an ACPI system, if it is */
470 /* Tell the kernel about all this */
471 IoReportHalResourceUsage(HalName
,
478 ExFreePool(TranslatedList
);
480 /* Get the machine's serial number */
481 HalpReportSerialNumber();
487 HalpRegisterVector(IN UCHAR Flags
,
489 IN ULONG SystemVector
,
492 /* Save the vector flags */
493 HalpIDTUsageFlags
[SystemVector
].Flags
= Flags
;
495 /* Save the vector data */
496 HalpIDTUsage
[SystemVector
].Irql
= Irql
;
497 HalpIDTUsage
[SystemVector
].BusReleativeVector
= BusVector
;
503 HalpEnableInterruptHandler(IN UCHAR Flags
,
505 IN ULONG SystemVector
,
508 IN KINTERRUPT_MODE Mode
)
510 /* Set the IDT_LATCHED flag for latched interrupts */
511 if (Mode
== Latched
) Flags
|= IDT_LATCHED
;
513 /* Register the vector */
514 HalpRegisterVector(Flags
, BusVector
, SystemVector
, Irql
);
516 /* Connect the interrupt */
517 KeRegisterInterruptHandler(SystemVector
, Handler
);
519 /* Enable the interrupt */
520 HalEnableSystemInterrupt(SystemVector
, Irql
, Mode
);
525 HalpGetNMICrashFlag(VOID
)
527 UNICODE_STRING ValueName
;
528 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
529 OBJECT_ATTRIBUTES ObjectAttributes
;
533 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
538 /* Initialize attributes */
539 InitializeObjectAttributes(&ObjectAttributes
,
541 OBJ_CASE_INSENSITIVE
,
546 Status
= ZwOpenKey(&Handle
, KEY_READ
, &ObjectAttributes
);
547 if (NT_SUCCESS(Status
))
549 /* Query key value */
550 RtlInitUnicodeString(&ValueName
, L
"NMICrashDump");
551 Status
= ZwQueryValueKey(Handle
,
553 KeyValuePartialInformation
,
554 &KeyValueInformation
,
555 sizeof(KeyValueInformation
),
557 if (NT_SUCCESS(Status
))
559 /* Check for valid data */
560 if (ResultLength
== sizeof(KEY_VALUE_PARTIAL_INFORMATION
))
563 HalpNMIDumpFlag
= KeyValueInformation
.Data
[0];