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 ******************************************************************/
65 HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
,
67 OUT PLARGE_INTEGER Value
)
69 /* Sorting depends on resource type */
70 switch (Descriptor
->Type
)
72 case CmResourceTypeInterrupt
:
74 /* Interrupt goes by level */
76 *Value
= RtlConvertUlongToLargeInteger(Descriptor
->u
.Interrupt
.Level
);
79 case CmResourceTypePort
:
81 /* Port goes by port address */
83 *Value
= Descriptor
->u
.Port
.Start
;
86 case CmResourceTypeMemory
:
88 /* Memory goes by base address */
90 *Value
= Descriptor
->u
.Memory
.Start
;
97 *Value
= RtlConvertUlongToLargeInteger(0);
104 HalpBuildPartialFromIdt(IN ULONG Entry
,
105 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
106 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
)
108 /* Exclusive interrupt entry */
109 RawDescriptor
->Type
= CmResourceTypeInterrupt
;
110 RawDescriptor
->ShareDisposition
= CmResourceShareDriverExclusive
;
112 /* Check the interrupt type */
113 if (HalpIDTUsageFlags
[Entry
].Flags
& IDT_LATCHED
)
116 RawDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LATCHED
;
121 RawDescriptor
->Flags
= CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE
;
124 /* Get vector and level from IDT usage */
125 RawDescriptor
->u
.Interrupt
.Vector
= HalpIDTUsage
[Entry
].BusReleativeVector
;
126 RawDescriptor
->u
.Interrupt
.Level
= HalpIDTUsage
[Entry
].BusReleativeVector
;
128 /* Affinity is all the CPUs */
129 RawDescriptor
->u
.Interrupt
.Affinity
= HalpActiveProcessors
;
131 /* The translated copy is identical */
132 RtlCopyMemory(TranslatedDescriptor
, RawDescriptor
, sizeof(TranslatedDescriptor
));
134 /* But the vector and IRQL must be set correctly */
135 TranslatedDescriptor
->u
.Interrupt
.Vector
= Entry
;
136 TranslatedDescriptor
->u
.Interrupt
.Level
= HalpIDTUsage
[Entry
].Irql
;
141 HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface
,
142 IN PADDRESS_USAGE CurrentAddress
,
144 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor
,
145 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
)
149 /* Set the type and make it exclusive */
150 RawDescriptor
->Type
= CurrentAddress
->Type
;
151 RawDescriptor
->ShareDisposition
= CmResourceShareDriverExclusive
;
153 /* Check what this is */
154 if (RawDescriptor
->Type
== CmResourceTypePort
)
156 /* Write out port data */
158 RawDescriptor
->Flags
= CM_RESOURCE_PORT_IO
;
159 RawDescriptor
->u
.Port
.Start
.HighPart
= 0;
160 RawDescriptor
->u
.Port
.Start
.LowPart
= CurrentAddress
->Element
[Element
].Start
;
161 RawDescriptor
->u
.Port
.Length
= CurrentAddress
->Element
[Element
].Length
;
163 /* Determine if 16-bit port addresses are allowed */
164 RawDescriptor
->Flags
|= HalpIs16BitPortDecodeSupported();
168 /* Write out memory data */
170 RawDescriptor
->Flags
= (CurrentAddress
->Flags
& IDT_READ_ONLY
) ?
171 CM_RESOURCE_MEMORY_READ_ONLY
:
172 CM_RESOURCE_MEMORY_READ_WRITE
;
173 RawDescriptor
->u
.Memory
.Start
.HighPart
= 0;
174 RawDescriptor
->u
.Memory
.Start
.LowPart
= CurrentAddress
->Element
[Element
].Start
;
175 RawDescriptor
->u
.Memory
.Length
= CurrentAddress
->Element
[Element
].Length
;
178 /* Make an identical copy to begin with */
179 RtlCopyMemory(TranslatedDescriptor
, RawDescriptor
, sizeof(TranslatedDescriptor
));
181 /* Check what this is */
182 if (RawDescriptor
->Type
== CmResourceTypePort
)
184 /* Translate the port */
185 HalTranslateBusAddress(Interface
,
187 RawDescriptor
->u
.Port
.Start
,
189 &TranslatedDescriptor
->u
.Port
.Start
);
191 /* If it turns out this is memory once translated, flag it */
192 if (AddressSpace
== 0) TranslatedDescriptor
->Flags
= CM_RESOURCE_PORT_MEMORY
;
197 /* Translate the memory */
198 HalTranslateBusAddress(Interface
,
200 RawDescriptor
->u
.Memory
.Start
,
202 &TranslatedDescriptor
->u
.Memory
.Start
);
208 HalpReportResourceUsage(IN PUNICODE_STRING HalName
,
209 IN INTERFACE_TYPE InterfaceType
)
211 PCM_RESOURCE_LIST RawList
, TranslatedList
;
212 PCM_FULL_RESOURCE_DESCRIPTOR RawFull
, TranslatedFull
;
213 PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw
, CurrentTranslated
, SortedRaw
, SortedTranslated
;
214 CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial
, TranslatedPartial
;
215 PCM_PARTIAL_RESOURCE_LIST RawPartialList
= NULL
, TranslatedPartialList
= NULL
;
216 INTERFACE_TYPE Interface
;
217 ULONG i
, j
, k
, ListSize
, Count
, Port
, Element
, CurrentScale
, SortScale
, ReportType
, FlagMatch
;
218 ADDRESS_USAGE
*CurrentAddress
;
219 LARGE_INTEGER CurrentSortValue
, SortValue
;
220 DbgPrint("%wZ Detected\n", HalName
);
222 /* Check if KD is using a COM port */
225 /* Enter it into the I/O space */
226 HalpComIoSpace
.Element
[0].Start
= (ULONG_PTR
)KdComPortInUse
;
227 HalpComIoSpace
.Next
= HalpAddressUsageList
;
228 HalpAddressUsageList
= &HalpComIoSpace
;
230 /* Use the debug port table if we have one */
231 HalpGetInfoFromACPI
= HalpGetDebugPortTable();
233 /* Check if we're using ACPI */
234 if (!HalpGetInfoFromACPI
)
236 /* No, so use our local table */
237 Port
= HalpComPortIrqMapping
[0][0];
238 for (i
= 0; Port
; i
++)
240 /* Is this the port we want? */
241 if (Port
== (ULONG_PTR
)KdComPortInUse
)
244 HalpRegisterVector(IDT_DEVICE
| IDT_LATCHED
,
245 HalpComPortIrqMapping
[i
][1],
246 HalpComPortIrqMapping
[i
][1] +
252 Port
= HalpComPortIrqMapping
[i
][0];
257 /* On non-ACPI systems, we need to build an address map */
258 HalpBuildAddressMap();
260 /* Allocate the master raw and translated lists */
261 RawList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, ' laH');
262 TranslatedList
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
* 2, ' laH');
263 if (!(RawList
) || !(TranslatedList
))
265 /* Bugcheck the system */
266 KeBugCheckEx(HAL_MEMORY_ALLOCATION
,
273 /* Zero out the lists */
274 RtlZeroMemory(RawList
, PAGE_SIZE
* 2);
275 RtlZeroMemory(TranslatedList
, PAGE_SIZE
* 2);
277 /* Set the interface type to begin with */
278 RawList
->List
[0].InterfaceType
= InterfaceTypeUndefined
;
280 /* Loop all IDT entries that are not IRQs */
281 for (i
= 0; i
< PRIMARY_VECTOR_BASE
; i
++)
283 /* Check if the IDT isn't owned */
284 if (!(HalpIDTUsageFlags
[i
].Flags
& IDT_REGISTERED
))
286 /* Then register it for internal usage */
287 HalpIDTUsageFlags
[i
].Flags
= IDT_INTERNAL
;
288 HalpIDTUsage
[i
].BusReleativeVector
= i
;
292 /* Our full raw descriptors start here */
293 RawFull
= RawList
->List
;
295 /* Keep track of the current partial raw and translated descriptors */
296 CurrentRaw
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)RawList
->List
;
297 CurrentTranslated
= (PCM_PARTIAL_RESOURCE_DESCRIPTOR
)TranslatedList
->List
;
300 for (ReportType
= 0; ReportType
< 2; ReportType
++)
302 /* Pass 0 is for device usage */
305 FlagMatch
= IDT_DEVICE
& ~IDT_REGISTERED
;
306 Interface
= InterfaceType
;
310 /* Past 1 is for internal HAL usage */
311 FlagMatch
= IDT_INTERNAL
& ~IDT_REGISTERED
;
312 Interface
= Internal
;
315 /* Reset loop variables */
318 /* Start looping our address uage list and interrupts */
319 CurrentAddress
= HalpAddressUsageList
;
322 /* Check for valid vector number */
323 if (i
<= MAXIMUM_IDTVECTOR
)
325 /* Check if this entry should be parsed */
326 if ((HalpIDTUsageFlags
[i
].Flags
& FlagMatch
))
329 HalpBuildPartialFromIdt(i
, &RawPartial
, &TranslatedPartial
);
334 /* Skip this entry */
341 /* This is an address instead */
342 if (!CurrentAddress
) break;
344 /* Check if the address should be reported */
345 if (!(CurrentAddress
->Flags
& FlagMatch
) ||
346 !(CurrentAddress
->Element
[Element
].Length
))
350 CurrentAddress
= CurrentAddress
->Next
;
354 /* Otherwise, parse the entry */
355 HalpBuildPartialFromAddress(Interface
,
363 /* Check for interface change */
364 if (RawFull
->InterfaceType
!= Interface
)
366 /* We need to add another full descriptor */
368 TranslatedList
->Count
++;
370 /* The full descriptor follows wherever we were */
371 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
372 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
374 /* And it is of this new interface type */
375 RawFull
->InterfaceType
= Interface
;
376 TranslatedFull
->InterfaceType
= Interface
;
378 /* And its partial descriptors begin here */
379 RawPartialList
= &RawFull
->PartialResourceList
;
380 TranslatedPartialList
= &TranslatedFull
->PartialResourceList
;
382 /* And our next full descriptor should follow here */
383 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
384 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
387 /* We have written a new partial descriptor */
388 RawPartialList
->Count
++;
389 TranslatedPartialList
->Count
++;
391 /* Copy our local descriptors into the actual list */
392 RtlCopyMemory(CurrentRaw
, &RawPartial
, sizeof(RawPartial
));
393 RtlCopyMemory(CurrentTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
395 /* Move to the next partial descriptor */
401 /* Get the final list of the size for the kernel call later */
402 ListSize
= (ULONG_PTR
)CurrentRaw
- (ULONG_PTR
)RawList
;
404 /* Now reset back to the first full descriptor */
405 RawFull
= RawList
->List
;
406 TranslatedFull
= TranslatedList
->List
;
408 /* And loop all the full descriptors */
409 for (i
= 0; i
< RawList
->Count
; i
++)
411 /* Get the first partial descriptor in this list */
412 CurrentRaw
= RawFull
->PartialResourceList
.PartialDescriptors
;
413 CurrentTranslated
= TranslatedFull
->PartialResourceList
.PartialDescriptors
;
415 /* Get the count of partials in this list */
416 Count
= RawFull
->PartialResourceList
.Count
;
418 /* Loop all the partials in this list */
419 for (j
= 0; j
< Count
; j
++)
421 /* Get the sort value at this point */
422 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
424 /* Save the current sort pointer */
425 SortedRaw
= CurrentRaw
;
426 SortedTranslated
= CurrentTranslated
;
428 /* Loop all descriptors starting from this one */
429 for (k
= j
; k
< Count
; k
++)
431 /* Get the sort value at the sort point */
432 HalpGetResourceSortValue(SortedRaw
, &SortScale
, &SortValue
);
434 /* Check if a swap needs to occur */
435 if ((SortScale
< CurrentScale
) ||
436 ((SortScale
== CurrentScale
) &&
437 (SortValue
.QuadPart
<= CurrentSortValue
.QuadPart
)))
439 /* Swap raw partial with the sort location partial */
440 RtlCopyMemory(&RawPartial
, CurrentRaw
, sizeof(RawPartial
));
441 RtlCopyMemory(CurrentRaw
, SortedRaw
, sizeof(RawPartial
));
442 RtlCopyMemory(SortedRaw
, &RawPartial
, sizeof(RawPartial
));
444 /* Swap translated partial in the same way */
445 RtlCopyMemory(&TranslatedPartial
, CurrentTranslated
, sizeof(TranslatedPartial
));
446 RtlCopyMemory(CurrentTranslated
, SortedTranslated
, sizeof(TranslatedPartial
));
447 RtlCopyMemory(SortedTranslated
, &TranslatedPartial
, sizeof(TranslatedPartial
));
449 /* Update the sort value at this point */
450 HalpGetResourceSortValue(CurrentRaw
, &CurrentScale
, &CurrentSortValue
);
453 /* The sort location has been updated */
458 /* Move to the next partial */
463 /* Move to the next full descriptor */
464 RawFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentRaw
;
465 TranslatedFull
= (PCM_FULL_RESOURCE_DESCRIPTOR
)CurrentTranslated
;
468 /* Mark this is an ACPI system, if it is */
471 /* Tell the kernel about all this */
472 IoReportHalResourceUsage(HalName
,
479 ExFreePool(TranslatedList
);
481 /* Get the machine's serial number */
482 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
)
512 /* Convert the vector into the IDT entry */
513 Entry
= HalVectorToIDTEntry(SystemVector
);
515 /* Register the vector */
516 HalpRegisterVector(Flags
, BusVector
, SystemVector
, Irql
);
518 /* Connect the interrupt */
519 ((PKIPCR
)KeGetPcr())->IDT
[Entry
].ExtendedOffset
= (USHORT
)(((ULONG_PTR
)Handler
>> 16) & 0xFFFF);
520 ((PKIPCR
)KeGetPcr())->IDT
[Entry
].Offset
= (USHORT
)((ULONG_PTR
)Handler
);
522 /* Enable the interrupt */
523 HalEnableSystemInterrupt(SystemVector
, Irql
, Mode
);
528 HalpGetNMICrashFlag(VOID
)
530 UNICODE_STRING ValueName
;
531 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
532 OBJECT_ATTRIBUTES ObjectAttributes
;
536 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
;
541 /* Initialize attributes */
542 InitializeObjectAttributes(&ObjectAttributes
,
544 OBJ_CASE_INSENSITIVE
,
549 Status
= ZwOpenKey(&Handle
, KEY_READ
, &ObjectAttributes
);
550 if (NT_SUCCESS(Status
))
552 /* Query key value */
553 RtlInitUnicodeString(&ValueName
, L
"NMICrashDump");
554 Status
= ZwQueryValueKey(Handle
,
556 KeyValuePartialInformation
,
557 &KeyValueInformation
,
558 sizeof(KeyValueInformation
),
560 if (NT_SUCCESS(Status
))
562 /* Check for valid data */
563 if (ResultLength
== sizeof(KEY_VALUE_PARTIAL_INFORMATION
))
566 HalpNMIDumpFlag
= KeyValueInformation
.Data
[0];