reactos/hal/halx86/generic/usage.c
Timo Kreuzer 71fefa32db
[NDK][NTOS] Add global definition of INIT_FUNCTION/INIT_SECTION (#779)
* Add an NDK header to define INIT_FUNCTION/INIT_SECTION globally
* Use _declspec(allocate(x)) and _declspec(code_seg(x)) on MSVC versions that support it
* Use INIT_FUNCTION on functions only and INIT_SECTION on data only (required by MSVC)
* Place INIT_FUNCTION before the return type (required by MSVC)
* Make sure declarations and implementations share the same modifiers (required by MSVC)
* Add a global linker option to suppress warnings about defined but unused INIT section
* Merge INIT section into .text in freeldr
2018-12-30 12:19:11 +01:00

620 lines
20 KiB
C

/*
* PROJECT: ReactOS HAL
* LICENSE: GPL - See COPYING in the top level directory
* FILE: hal/halx86/generic/usage.c
* PURPOSE: HAL Resource Report Routines
* PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org)
*/
/* INCLUDES *******************************************************************/
#include <hal.h>
#define NDEBUG
#include <debug.h>
INIT_FUNCTION
VOID
NTAPI
HalpGetResourceSortValue(
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
OUT PULONG Scale,
OUT PLARGE_INTEGER Value
);
INIT_FUNCTION
VOID
NTAPI
HalpBuildPartialFromIdt(
IN ULONG Entry,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
);
INIT_FUNCTION
VOID
NTAPI
HalpBuildPartialFromAddress(
IN INTERFACE_TYPE Interface,
IN PADDRESS_USAGE CurrentAddress,
IN ULONG Element,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor
);
#if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_)
#pragma alloc_text(INIT, HalpBuildPartialFromAddress)
#pragma alloc_text(INIT, HalpBuildPartialFromIdt)
#pragma alloc_text(INIT, HalpEnableInterruptHandler)
#pragma alloc_text(INIT, HalpGetNMICrashFlag)
#pragma alloc_text(INIT, HalpGetResourceSortValue)
#pragma alloc_text(INIT, HalpRegisterVector)
#pragma alloc_text(INIT, HalpReportResourceUsage)
#endif
/* GLOBALS ********************************************************************/
BOOLEAN HalpGetInfoFromACPI;
BOOLEAN HalpNMIDumpFlag;
PUCHAR KdComPortInUse;
PADDRESS_USAGE HalpAddressUsageList;
IDTUsageFlags HalpIDTUsageFlags[MAXIMUM_IDTVECTOR+1];
IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR+1];
USHORT HalpComPortIrqMapping[5][2] =
{
{0x3F8, 4},
{0x2F8, 3},
{0x3E8, 4},
{0x2E8, 3},
{0, 0}
};
ADDRESS_USAGE HalpComIoSpace =
{
NULL, CmResourceTypePort, IDT_INTERNAL,
{
{0x2F8, 0x8}, /* COM 1 */
{0,0},
}
};
ADDRESS_USAGE HalpDefaultIoSpace =
{
NULL, CmResourceTypePort, IDT_INTERNAL,
{
{0x00, 0x20}, /* DMA 1 */
{0xC0, 0x20}, /* DMA 2 */
{0x80, 0x10}, /* DMA EPAR */
{0x20, 0x2}, /* PIC 1 */
{0xA0, 0x2}, /* PIC 2 */
{0x40, 0x4}, /* PIT 1 */
{0x48, 0x4}, /* PIT 2 */
{0x92, 0x1}, /* System Control Port A */
{0x70, 0x2}, /* CMOS */
{0xF0, 0x10}, /* x87 Coprocessor */
{0xCF8, 0x8}, /* PCI 0 */
{0,0},
}
};
/* FUNCTIONS ******************************************************************/
#ifndef _MINIHAL_
INIT_FUNCTION
VOID
NTAPI
HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
OUT PULONG Scale,
OUT PLARGE_INTEGER Value)
{
/* Sorting depends on resource type */
switch (Descriptor->Type)
{
case CmResourceTypeInterrupt:
/* Interrupt goes by level */
*Scale = 0;
*Value = RtlConvertUlongToLargeInteger(Descriptor->u.Interrupt.Level);
break;
case CmResourceTypePort:
/* Port goes by port address */
*Scale = 1;
*Value = Descriptor->u.Port.Start;
break;
case CmResourceTypeMemory:
/* Memory goes by base address */
*Scale = 2;
*Value = Descriptor->u.Memory.Start;
break;
default:
/* Anything else */
*Scale = 4;
*Value = RtlConvertUlongToLargeInteger(0);
break;
}
}
INIT_FUNCTION
VOID
NTAPI
HalpBuildPartialFromIdt(IN ULONG Entry,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor)
{
/* Exclusive interrupt entry */
RawDescriptor->Type = CmResourceTypeInterrupt;
RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
/* Check the interrupt type */
if (HalpIDTUsageFlags[Entry].Flags & IDT_LATCHED)
{
/* Latched */
RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
}
else
{
/* Level */
RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
}
/* Get vector and level from IDT usage */
RawDescriptor->u.Interrupt.Vector = HalpIDTUsage[Entry].BusReleativeVector;
RawDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].BusReleativeVector;
/* Affinity is all the CPUs */
RawDescriptor->u.Interrupt.Affinity = HalpActiveProcessors;
/* The translated copy is identical */
RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
/* But the vector and IRQL must be set correctly */
TranslatedDescriptor->u.Interrupt.Vector = Entry;
TranslatedDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].Irql;
}
INIT_FUNCTION
VOID
NTAPI
HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface,
IN PADDRESS_USAGE CurrentAddress,
IN ULONG Element,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor,
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor)
{
ULONG AddressSpace;
/* Set the type and make it exclusive */
RawDescriptor->Type = CurrentAddress->Type;
RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
/* Check what this is */
if (RawDescriptor->Type == CmResourceTypePort)
{
/* Write out port data */
AddressSpace = 1;
RawDescriptor->Flags = CM_RESOURCE_PORT_IO;
RawDescriptor->u.Port.Start.HighPart = 0;
RawDescriptor->u.Port.Start.LowPart = CurrentAddress->Element[Element].Start;
RawDescriptor->u.Port.Length = CurrentAddress->Element[Element].Length;
/* Determine if 16-bit port addresses are allowed */
RawDescriptor->Flags |= HalpIs16BitPortDecodeSupported();
}
else
{
/* Write out memory data */
AddressSpace = 0;
RawDescriptor->Flags = (CurrentAddress->Flags & IDT_READ_ONLY) ?
CM_RESOURCE_MEMORY_READ_ONLY :
CM_RESOURCE_MEMORY_READ_WRITE;
RawDescriptor->u.Memory.Start.HighPart = 0;
RawDescriptor->u.Memory.Start.LowPart = CurrentAddress->Element[Element].Start;
RawDescriptor->u.Memory.Length = CurrentAddress->Element[Element].Length;
}
/* Make an identical copy to begin with */
RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
/* Check what this is */
if (RawDescriptor->Type == CmResourceTypePort)
{
/* Translate the port */
HalTranslateBusAddress(Interface,
0,
RawDescriptor->u.Port.Start,
&AddressSpace,
&TranslatedDescriptor->u.Port.Start);
/* If it turns out this is memory once translated, flag it */
if (AddressSpace == 0) TranslatedDescriptor->Flags = CM_RESOURCE_PORT_MEMORY;
}
else
{
/* Translate the memory */
HalTranslateBusAddress(Interface,
0,
RawDescriptor->u.Memory.Start,
&AddressSpace,
&TranslatedDescriptor->u.Memory.Start);
}
}
INIT_FUNCTION
VOID
NTAPI
HalpReportResourceUsage(IN PUNICODE_STRING HalName,
IN INTERFACE_TYPE InterfaceType)
{
PCM_RESOURCE_LIST RawList, TranslatedList;
PCM_FULL_RESOURCE_DESCRIPTOR RawFull, TranslatedFull;
PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw, CurrentTranslated, SortedRaw, SortedTranslated;
CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial, TranslatedPartial;
PCM_PARTIAL_RESOURCE_LIST RawPartialList = NULL, TranslatedPartialList = NULL;
INTERFACE_TYPE Interface;
ULONG i, j, k, ListSize, Count, Port, Element, CurrentScale, SortScale, ReportType, FlagMatch;
ADDRESS_USAGE *CurrentAddress;
LARGE_INTEGER CurrentSortValue, SortValue;
DbgPrint("%wZ Detected\n", HalName);
/* Check if KD is using a COM port */
if (KdComPortInUse)
{
/* Enter it into the I/O space */
HalpComIoSpace.Element[0].Start = PtrToUlong(KdComPortInUse);
HalpComIoSpace.Next = HalpAddressUsageList;
HalpAddressUsageList = &HalpComIoSpace;
/* Use the debug port table if we have one */
HalpGetInfoFromACPI = HalpGetDebugPortTable();
/* Check if we're using ACPI */
if (!HalpGetInfoFromACPI)
{
/* No, so use our local table */
for (i = 0, Port = HalpComPortIrqMapping[i][0];
Port;
i++, Port = HalpComPortIrqMapping[i][0])
{
/* Is this the port we want? */
if (Port == (ULONG_PTR)KdComPortInUse)
{
/* Register it */
HalpRegisterVector(IDT_DEVICE | IDT_LATCHED,
HalpComPortIrqMapping[i][1],
HalpComPortIrqMapping[i][1] +
PRIMARY_VECTOR_BASE,
HIGH_LEVEL);
}
}
}
}
/* On non-ACPI systems, we need to build an address map */
HalpBuildAddressMap();
/* Allocate the master raw and translated lists */
RawList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL);
TranslatedList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, TAG_HAL);
if (!(RawList) || !(TranslatedList))
{
/* Bugcheck the system */
KeBugCheckEx(HAL_MEMORY_ALLOCATION,
4 * PAGE_SIZE,
1,
(ULONG_PTR)__FILE__,
__LINE__);
}
/* Zero out the lists */
RtlZeroMemory(RawList, PAGE_SIZE * 2);
RtlZeroMemory(TranslatedList, PAGE_SIZE * 2);
/* Set the interface type to begin with */
RawList->List[0].InterfaceType = InterfaceTypeUndefined;
/* Loop all IDT entries that are not IRQs */
for (i = 0; i < PRIMARY_VECTOR_BASE; i++)
{
/* Check if the IDT isn't owned */
if (!(HalpIDTUsageFlags[i].Flags & IDT_REGISTERED))
{
/* Then register it for internal usage */
HalpIDTUsageFlags[i].Flags = IDT_INTERNAL;
HalpIDTUsage[i].BusReleativeVector = (UCHAR)i;
}
}
/* Our full raw descriptors start here */
RawFull = RawList->List;
/* Keep track of the current partial raw and translated descriptors */
CurrentRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)RawList->List;
CurrentTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)TranslatedList->List;
/* Do two passes */
for (ReportType = 0; ReportType < 2; ReportType++)
{
/* Pass 0 is for device usage */
if (ReportType == 0)
{
FlagMatch = IDT_DEVICE & ~IDT_REGISTERED;
Interface = InterfaceType;
}
else
{
/* Past 1 is for internal HAL usage */
FlagMatch = IDT_INTERNAL & ~IDT_REGISTERED;
Interface = Internal;
}
/* Reset loop variables */
i = Element = 0;
/* Start looping our address uage list and interrupts */
CurrentAddress = HalpAddressUsageList;
while (TRUE)
{
/* Check for valid vector number */
if (i <= MAXIMUM_IDTVECTOR)
{
/* Check if this entry should be parsed */
if ((HalpIDTUsageFlags[i].Flags & FlagMatch))
{
/* Parse it */
HalpBuildPartialFromIdt(i, &RawPartial, &TranslatedPartial);
i++;
}
else
{
/* Skip this entry */
i++;
continue;
}
}
else
{
/* This is an address instead */
if (!CurrentAddress) break;
/* Check if the address should be reported */
if (!(CurrentAddress->Flags & FlagMatch) ||
!(CurrentAddress->Element[Element].Length))
{
/* Nope, skip it */
Element = 0;
CurrentAddress = CurrentAddress->Next;
continue;
}
/* Otherwise, parse the entry */
HalpBuildPartialFromAddress(Interface,
CurrentAddress,
Element,
&RawPartial,
&TranslatedPartial);
Element++;
}
/* Check for interface change */
if (RawFull->InterfaceType != Interface)
{
/* We need to add another full descriptor */
RawList->Count++;
TranslatedList->Count++;
/* The full descriptor follows wherever we were */
RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
/* And it is of this new interface type */
RawFull->InterfaceType = Interface;
TranslatedFull->InterfaceType = Interface;
/* And its partial descriptors begin here */
RawPartialList = &RawFull->PartialResourceList;
TranslatedPartialList = &TranslatedFull->PartialResourceList;
/* And our next full descriptor should follow here */
CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
}
/* We have written a new partial descriptor */
RawPartialList->Count++;
TranslatedPartialList->Count++;
/* Copy our local descriptors into the actual list */
RtlCopyMemory(CurrentRaw, &RawPartial, sizeof(RawPartial));
RtlCopyMemory(CurrentTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
/* Move to the next partial descriptor */
CurrentRaw++;
CurrentTranslated++;
}
}
/* Get the final list of the size for the kernel call later */
ListSize = (ULONG)((ULONG_PTR)CurrentRaw - (ULONG_PTR)RawList);
/* Now reset back to the first full descriptor */
RawFull = RawList->List;
TranslatedFull = TranslatedList->List;
/* And loop all the full descriptors */
for (i = 0; i < RawList->Count; i++)
{
/* Get the first partial descriptor in this list */
CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
/* Get the count of partials in this list */
Count = RawFull->PartialResourceList.Count;
/* Loop all the partials in this list */
for (j = 0; j < Count; j++)
{
/* Get the sort value at this point */
HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
/* Save the current sort pointer */
SortedRaw = CurrentRaw;
SortedTranslated = CurrentTranslated;
/* Loop all descriptors starting from this one */
for (k = j; k < Count; k++)
{
/* Get the sort value at the sort point */
HalpGetResourceSortValue(SortedRaw, &SortScale, &SortValue);
/* Check if a swap needs to occur */
if ((SortScale < CurrentScale) ||
((SortScale == CurrentScale) &&
(SortValue.QuadPart <= CurrentSortValue.QuadPart)))
{
/* Swap raw partial with the sort location partial */
RtlCopyMemory(&RawPartial, CurrentRaw, sizeof(RawPartial));
RtlCopyMemory(CurrentRaw, SortedRaw, sizeof(RawPartial));
RtlCopyMemory(SortedRaw, &RawPartial, sizeof(RawPartial));
/* Swap translated partial in the same way */
RtlCopyMemory(&TranslatedPartial, CurrentTranslated, sizeof(TranslatedPartial));
RtlCopyMemory(CurrentTranslated, SortedTranslated, sizeof(TranslatedPartial));
RtlCopyMemory(SortedTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
/* Update the sort value at this point */
HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
}
/* The sort location has been updated */
SortedRaw++;
SortedTranslated++;
}
/* Move to the next partial */
CurrentRaw++;
CurrentTranslated++;
}
/* Move to the next full descriptor */
RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
}
/* Mark this is an ACPI system, if it is */
HalpMarkAcpiHal();
/* Tell the kernel about all this */
IoReportHalResourceUsage(HalName,
RawList,
TranslatedList,
ListSize);
/* Free our lists */
ExFreePool(RawList);
ExFreePool(TranslatedList);
/* Get the machine's serial number */
HalpReportSerialNumber();
}
#endif
INIT_FUNCTION
VOID
NTAPI
HalpRegisterVector(IN UCHAR Flags,
IN ULONG BusVector,
IN ULONG SystemVector,
IN KIRQL Irql)
{
/* Save the vector flags */
HalpIDTUsageFlags[SystemVector].Flags = Flags;
/* Save the vector data */
HalpIDTUsage[SystemVector].Irql = Irql;
HalpIDTUsage[SystemVector].BusReleativeVector = (UCHAR)BusVector;
}
#ifndef _MINIHAL_
INIT_FUNCTION
VOID
NTAPI
HalpEnableInterruptHandler(IN UCHAR Flags,
IN ULONG BusVector,
IN ULONG SystemVector,
IN KIRQL Irql,
IN PVOID Handler,
IN KINTERRUPT_MODE Mode)
{
/* Set the IDT_LATCHED flag for latched interrupts */
if (Mode == Latched) Flags |= IDT_LATCHED;
/* Register the vector */
HalpRegisterVector(Flags, BusVector, SystemVector, Irql);
/* Connect the interrupt */
KeRegisterInterruptHandler(SystemVector, Handler);
/* Enable the interrupt */
HalEnableSystemInterrupt(SystemVector, Irql, Mode);
}
INIT_FUNCTION
VOID
NTAPI
HalpGetNMICrashFlag(VOID)
{
UNICODE_STRING ValueName;
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG ResultLength;
HANDLE Handle;
NTSTATUS Status;
KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
/* Set default */
HalpNMIDumpFlag = 0;
/* Initialize attributes */
InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Open crash key */
Status = ZwOpenKey(&Handle, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status))
{
/* Query key value */
RtlInitUnicodeString(&ValueName, L"NMICrashDump");
Status = ZwQueryValueKey(Handle,
&ValueName,
KeyValuePartialInformation,
&KeyValueInformation,
sizeof(KeyValueInformation),
&ResultLength);
if (NT_SUCCESS(Status))
{
/* Check for valid data */
if (ResultLength == sizeof(KEY_VALUE_PARTIAL_INFORMATION))
{
/* Read the flag */
HalpNMIDumpFlag = KeyValueInformation.Data[0];
}
}
/* We're done */
ZwClose(Handle);
}
}
#endif
/* EOF */