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
+1];
22 IDTUsage HalpIDTUsage
[MAXIMUM_IDTVECTOR
+1];
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 {0x00, 0x20}, /* DMA 1 */
47 {0xC0, 0x20}, /* DMA 2 */
48 {0x80, 0x10}, /* DMA EPAR */
49 {0x20, 0x2}, /* PIC 1 */
50 {0xA0, 0x2}, /* PIC 2 */
51 {0x40, 0x4}, /* PIT 1 */
52 {0x48, 0x4}, /* PIT 2 */
53 {0x92, 0x1}, /* System Control Port A */
54 {0x70, 0x2}, /* CMOS */
55 {0xF0, 0x10}, /* x87 Coprocessor */
56 {0xCF8, 0x8}, /* PCI 0 */
61 /* FUNCTIONS ******************************************************************/
67 HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
,
69 OUT PLARGE_INTEGER Value
)
71 /* Sorting depends on resource type */
72 switch (Descriptor
->Type
)
74 case CmResourceTypeInterrupt
:
76 /* Interrupt goes by level */
78 *Value
= RtlConvertUlongToLargeInteger(Descriptor
->u
.Interrupt
.Level
);
81 case CmResourceTypePort
:
83 /* Port goes by port address */
85 *Value
= Descriptor
->u
.Port
.Start
;
88 case CmResourceTypeMemory
:
90 /* Memory goes by base address */
92 *Value
= Descriptor
->u
.Memory
.Start
;
99 *Value
= RtlConvertUlongToLargeInteger(0);
107 HalpBuildPartialFromIdt(IN ULONG Entry
,
108 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
109 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
)
111 /* Exclusive interrupt entry */
112 RawDescriptor
->Type
= CmResourceTypeInterrupt
;
113 RawDescriptor
->ShareDisposition
= CmResourceShareDriverExclusive
;
115 /* Check the interrupt type */
116 if (HalpIDTUsageFlags
[Entry
].Flags
& IDT_LATCHED
)
119 RawDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
124 RawDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
127 /* Get vector and level from IDT usage */
128 RawDescriptor
->u
.Interrupt
.Vector
= HalpIDTUsage
[Entry
].BusReleativeVector
;
129 RawDescriptor
->u
.Interrupt
.Level
= HalpIDTUsage
[Entry
].BusReleativeVector
;
131 /* Affinity is all the CPUs */
132 RawDescriptor
->u
.Interrupt
.Affinity
= HalpActiveProcessors
;
134 /* The translated copy is identical */
135 RtlCopyMemory(TranslatedDescriptor
, RawDescriptor
, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
137 /* But the vector and IRQL must be set correctly */
138 TranslatedDescriptor
->u
.Interrupt
.Vector
= Entry
;
139 TranslatedDescriptor
->u
.Interrupt
.Level
= HalpIDTUsage
[Entry
].Irql
;
145 HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface
,
146 IN PADDRESS_USAGE CurrentAddress
,
148 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
149 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
)
153 /* Set the type and make it exclusive */
154 RawDescriptor
->Type
= CurrentAddress
->Type
;
155 RawDescriptor
->ShareDisposition
= CmResourceShareDriverExclusive
;
157 /* Check what this is */
158 if (RawDescriptor
->Type
== CmResourceTypePort
)
160 /* Write out port data */
162 RawDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
163 RawDescriptor
->u
.Port
.Start
.HighPart
= 0;
164 RawDescriptor
->u
.Port
.Start
.LowPart
= CurrentAddress
->Element
[Element
].Start
;
165 RawDescriptor
->u
.Port
.Length
= CurrentAddress
->Element
[Element
].Length
;
167 /* Determine if 16-bit port addresses are allowed */
168 RawDescriptor
->Flags
|= HalpIs16BitPortDecodeSupported();
172 /* Write out memory data */
174 RawDescriptor
->Flags
= (CurrentAddress
->Flags
& IDT_READ_ONLY
) ?
175 CM_RESOURCE_MEMORY_READ_ONLY
:
176 CM_RESOURCE_MEMORY_READ_WRITE
;
177 RawDescriptor
->u
.Memory
.Start
.HighPart
= 0;
178 RawDescriptor
->u
.Memory
.Start
.LowPart
= CurrentAddress
->Element
[Element
].Start
;
179 RawDescriptor
->u
.Memory
.Length
= CurrentAddress
->Element
[Element
].Length
;
182 /* Make an identical copy to begin with */
183 RtlCopyMemory(TranslatedDescriptor
, RawDescriptor
, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR
));
185 /* Check what this is */
186 if (RawDescriptor
->Type
== CmResourceTypePort
)
188 /* Translate the port */
189 HalTranslateBusAddress(Interface
,
191 RawDescriptor
->u
.Port
.Start
,
193 &TranslatedDescriptor
->u
.Port
.Start
);
195 /* If it turns out this is memory once translated, flag it */
196 if (AddressSpace
== 0) TranslatedDescriptor
->Flags
= CM_RESOURCE_PORT_MEMORY
;
201 /* Translate the memory */
202 HalTranslateBusAddress(Interface
,
204 RawDescriptor
->u
.Memory
.Start
,
206 &TranslatedDescriptor
->u
.Memory
.Start
);
213 HalpReportResourceUsage(IN PUNICODE_STRING HalName
,
214 IN INTERFACE_TYPE InterfaceType
)
216 PCM_RESOURCE_LIST RawList
, TranslatedList
;
217 PCM_FULL_RESOURCE_DESCRIPTOR RawFull
, TranslatedFull
;
218 PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw
, CurrentTranslated
, SortedRaw
, SortedTranslated
;
219 CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial
, TranslatedPartial
;
220 PCM_PARTIAL_RESOURCE_LIST RawPartialList
= NULL
, TranslatedPartialList
= NULL
;
221 INTERFACE_TYPE Interface
;
222 ULONG i
, j
, k
, ListSize
, Count
, Port
, Element
, CurrentScale
, SortScale
, ReportType
, FlagMatch
;
223 ADDRESS_USAGE
*CurrentAddress
;
224 LARGE_INTEGER CurrentSortValue
, SortValue
;
225 DbgPrint("%wZ Detected\n", HalName
);
227 /* Check if KD is using a COM port */
230 /* Enter it into the I/O space */
231 HalpComIoSpace
.Element
[0].Start
= PtrToUlong(KdComPortInUse
);
232 HalpComIoSpace
.Next
= HalpAddressUsageList
;
233 HalpAddressUsageList
= &HalpComIoSpace
;
235 /* Use the debug port table if we have one */
236 HalpGetInfoFromACPI
= HalpGetDebugPortTable();
238 /* Check if we're using ACPI */
239 if (!HalpGetInfoFromACPI
)
241 /* No, so use our local table */
242 for (i
= 0, Port
= HalpComPortIrqMapping
[i
][0];
244 i
++, Port
= HalpComPortIrqMapping
[i
][0])
246 /* Is this the port we want? */
247 if (Port
== (ULONG_PTR
)KdComPortInUse
)
250 HalpRegisterVector(IDT_DEVICE
| IDT_LATCHED
,
251 HalpComPortIrqMapping
[i
][1],
252 HalpComPortIrqMapping
[i
][1] +
260 /* On non-ACPI systems, we need to build an address map */
261 HalpBuildAddressMap();
263 /* Allocate the master raw and translated lists */
264 RawList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, TAG_HAL
);
265 TranslatedList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, TAG_HAL
);
266 if (!(RawList
) || !(TranslatedList
))
268 /* Bugcheck the system */
269 KeBugCheckEx(HAL_MEMORY_ALLOCATION
,
276 /* Zero out the lists */
277 RtlZeroMemory(RawList
, PAGE_SIZE
* 2);
278 RtlZeroMemory(TranslatedList
, PAGE_SIZE
* 2);
280 /* Set the interface type to begin with */
281 RawList
->List
[0].InterfaceType
= InterfaceTypeUndefined
;
283 /* Loop all IDT entries that are not IRQs */
284 for (i
= 0; i
< PRIMARY_VECTOR_BASE
; i
++)
286 /* Check if the IDT isn't owned */
287 if (!(HalpIDTUsageFlags
[i
].Flags
& IDT_REGISTERED
))
289 /* Then register it for internal usage */
290 HalpIDTUsageFlags
[i
].Flags
= IDT_INTERNAL
;
291 HalpIDTUsage
[i
].BusReleativeVector
= (UCHAR
)i
;
295 /* Our full raw descriptors start here */
296 RawFull
= RawList
->List
;
298 /* Keep track of the current partial raw and translated descriptors */
299 CurrentRaw
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)RawList
->List
;
300 CurrentTranslated
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)TranslatedList
->List
;
303 for (ReportType
= 0; ReportType
< 2; ReportType
++)
305 /* Pass 0 is for device usage */
308 FlagMatch
= IDT_DEVICE
& ~IDT_REGISTERED
;
309 Interface
= InterfaceType
;
313 /* Past 1 is for internal HAL usage */
314 FlagMatch
= IDT_INTERNAL
& ~IDT_REGISTERED
;
315 Interface
= Internal
;
318 /* Reset loop variables */
321 /* Start looping our address uage list and interrupts */
322 CurrentAddress
= HalpAddressUsageList
;
325 /* Check for valid vector number */
326 if (i
<= MAXIMUM_IDTVECTOR
)
328 /* Check if this entry should be parsed */
329 if ((HalpIDTUsageFlags
[i
].Flags
& FlagMatch
))
332 HalpBuildPartialFromIdt(i
, &RawPartial
, &TranslatedPartial
);
337 /* Skip this entry */
344 /* This is an address instead */
345 if (!CurrentAddress
) break;
347 /* Check if the address should be reported */
348 if (!(CurrentAddress
->Flags
& FlagMatch
) ||
349 !(CurrentAddress
->Element
[Element
].Length
))
353 CurrentAddress
= CurrentAddress
->Next
;
357 /* Otherwise, parse the entry */
358 HalpBuildPartialFromAddress(Interface
,
366 /* Check for interface change */
367 if (RawFull
->InterfaceType
!= Interface
)
369 /* We need to add another full descriptor */
371 TranslatedList
->Count
++;
373 /* The full descriptor follows wherever we were */
374 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
375 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
377 /* And it is of this new interface type */
378 RawFull
->InterfaceType
= Interface
;
379 TranslatedFull
->InterfaceType
= Interface
;
381 /* And its partial descriptors begin here */
382 RawPartialList
= &RawFull
->PartialResourceList
;
383 TranslatedPartialList
= &TranslatedFull
->PartialResourceList
;
385 /* And our next full descriptor should follow here */
386 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
387 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
390 /* We have written a new partial descriptor */
391 RawPartialList
->Count
++;
392 TranslatedPartialList
->Count
++;
394 /* Copy our local descriptors into the actual list */
395 RtlCopyMemory(CurrentRaw
, &RawPartial
, sizeof(RawPartial
));
396 RtlCopyMemory(CurrentTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
398 /* Move to the next partial descriptor */
404 /* Get the final list of the size for the kernel call later */
405 ListSize
= (ULONG
)((ULONG_PTR
)CurrentRaw
- (ULONG_PTR
)RawList
);
407 /* Now reset back to the first full descriptor */
408 RawFull
= RawList
->List
;
409 TranslatedFull
= TranslatedList
->List
;
411 /* And loop all the full descriptors */
412 for (i
= 0; i
< RawList
->Count
; i
++)
414 /* Get the first partial descriptor in this list */
415 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
416 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
418 /* Get the count of partials in this list */
419 Count
= RawFull
->PartialResourceList
.Count
;
421 /* Loop all the partials in this list */
422 for (j
= 0; j
< Count
; j
++)
424 /* Get the sort value at this point */
425 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
427 /* Save the current sort pointer */
428 SortedRaw
= CurrentRaw
;
429 SortedTranslated
= CurrentTranslated
;
431 /* Loop all descriptors starting from this one */
432 for (k
= j
; k
< Count
; k
++)
434 /* Get the sort value at the sort point */
435 HalpGetResourceSortValue(SortedRaw
, &SortScale
, &SortValue
);
437 /* Check if a swap needs to occur */
438 if ((SortScale
< CurrentScale
) ||
439 ((SortScale
== CurrentScale
) &&
440 (SortValue
.QuadPart
<= CurrentSortValue
.QuadPart
)))
442 /* Swap raw partial with the sort location partial */
443 RtlCopyMemory(&RawPartial
, CurrentRaw
, sizeof(RawPartial
));
444 RtlCopyMemory(CurrentRaw
, SortedRaw
, sizeof(RawPartial
));
445 RtlCopyMemory(SortedRaw
, &RawPartial
, sizeof(RawPartial
));
447 /* Swap translated partial in the same way */
448 RtlCopyMemory(&TranslatedPartial
, CurrentTranslated
, sizeof(TranslatedPartial
));
449 RtlCopyMemory(CurrentTranslated
, SortedTranslated
, sizeof(TranslatedPartial
));
450 RtlCopyMemory(SortedTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
452 /* Update the sort value at this point */
453 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
456 /* The sort location has been updated */
461 /* Move to the next partial */
466 /* Move to the next full descriptor */
467 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
468 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
471 /* Mark this is an ACPI system, if it is */
474 /* Tell the kernel about all this */
475 IoReportHalResourceUsage(HalName
,
482 ExFreePool(TranslatedList
);
484 /* Get the machine's serial number */
485 HalpReportSerialNumber();
492 HalpRegisterVector(IN UCHAR Flags
,
494 IN ULONG SystemVector
,
497 /* Save the vector flags */
498 HalpIDTUsageFlags
[SystemVector
].Flags
= Flags
;
500 /* Save the vector data */
501 HalpIDTUsage
[SystemVector
].Irql
= Irql
;
502 HalpIDTUsage
[SystemVector
].BusReleativeVector
= (UCHAR
)BusVector
;
509 HalpEnableInterruptHandler(IN UCHAR Flags
,
511 IN ULONG SystemVector
,
514 IN KINTERRUPT_MODE Mode
)
516 /* Set the IDT_LATCHED flag for latched interrupts */
517 if (Mode
== Latched
) Flags
|= IDT_LATCHED
;
519 /* Register the vector */
520 HalpRegisterVector(Flags
, BusVector
, SystemVector
, Irql
);
522 /* Connect the interrupt */
523 KeRegisterInterruptHandler(SystemVector
, Handler
);
525 /* Enable the interrupt */
526 HalEnableSystemInterrupt(SystemVector
, Irql
, Mode
);
532 HalpGetNMICrashFlag(VOID
)
534 UNICODE_STRING ValueName
;
535 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
536 OBJECT_ATTRIBUTES ObjectAttributes
;
540 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
545 /* Initialize attributes */
546 InitializeObjectAttributes(&ObjectAttributes
,
548 OBJ_CASE_INSENSITIVE
,
553 Status
= ZwOpenKey(&Handle
, KEY_READ
, &ObjectAttributes
);
554 if (NT_SUCCESS(Status
))
556 /* Query key value */
557 RtlInitUnicodeString(&ValueName
, L
"NMICrashDump");
558 Status
= ZwQueryValueKey(Handle
,
560 KeyValuePartialInformation
,
561 &KeyValueInformation
,
562 sizeof(KeyValueInformation
),
564 if (NT_SUCCESS(Status
))
566 /* Check for valid data */
567 if (ResultLength
== sizeof(KEY_VALUE_PARTIAL_INFORMATION
))
570 HalpNMIDumpFlag
= KeyValueInformation
.Data
[0];