windows-nt/Source/XPSP1/NT/base/hals/halx86/i386/ixinfo.c
2020-09-26 16:20:57 +08:00

696 lines
20 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1991-2000 Microsoft Corporation
Module Name:
ixinfo.c
Abstract:
Author:
Ken Reneris (kenr) 08-Aug-1994
Environment:
Kernel mode only.
Revision History:
--*/
#include "halp.h"
#include "pci.h"
#include "pcip.h"
#ifdef _PNP_POWER_
HAL_CALLBACKS HalCallback;
extern WCHAR rgzSuspendCallbackName[];
VOID
HalInitSystemPhase2 (
VOID
);
VOID
HalpLockSuspendCode (
IN PVOID CallbackContext,
IN PVOID Argument1,
IN PVOID Argument2
);
#endif
NTSTATUS
HalpQueryInstalledBusInformation (
OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnedLength
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,HaliQuerySystemInformation)
#pragma alloc_text(PAGE,HaliSetSystemInformation)
#pragma alloc_text(INIT,HalInitSystemPhase2)
#ifdef _PNP_POWER_
#pragma alloc_text(PAGE,HalpLockSuspendCode)
#endif
#endif
//
// HalQueryMcaInterface
//
VOID
HalpMcaLockInterface(
VOID
);
VOID
HalpMcaUnlockInterface(
VOID
);
NTSTATUS
HalpMcaReadRegisterInterface(
IN UCHAR BankNumber,
IN OUT PMCA_EXCEPTION Exception
);
#ifdef ACPI_HAL
extern PHYSICAL_ADDRESS HalpMaxHotPlugMemoryAddress;
#endif
#if defined(ACPI_HAL) && defined(_HALPAE_) && !defined(NT_UP)
extern PVOID HalpAcpiSrat;
NTSTATUS
HalpGetAcpiStaticNumaTopology(
HAL_NUMA_TOPOLOGY_INTERFACE * NumaInfo
);
#endif
VOID
HalInitSystemPhase2 (
VOID
)
{
#ifdef _PNP_POWER_
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
UNICODE_STRING unicodeString;
PCALLBACK_OBJECT CallbackObject;
//
// Create hal callbacks
//
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
ExCreateCallback (&HalCallback.SetSystemInformation, &ObjectAttributes, TRUE, TRUE);
ExCreateCallback (&HalCallback.BusCheck, &ObjectAttributes, TRUE, TRUE);
//
// Connect to suspend callback to lock hal hibaration code
//
RtlInitUnicodeString(&unicodeString, rgzSuspendCallbackName);
InitializeObjectAttributes(
&ObjectAttributes,
&unicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = ExCreateCallback (&CallbackObject, &ObjectAttributes, FALSE, FALSE);
if (NT_SUCCESS(Status)) {
ExRegisterCallback (
CallbackObject,
HalpLockSuspendCode,
NULL
);
ObDereferenceObject (CallbackObject);
}
#endif
}
#if defined(_HALPAE_) && !defined(NT_UP)
NTSTATUS
HalpGetApicIdByProcessorNumber(
IN UCHAR Processor,
IN OUT USHORT *ApicId
);
ULONG HalpFakeNumaNodes;
ULONG HalpFakeNumaAffinity;
ULONG HalpFakeNumaAffinityShift;
ULONG HalpFakeNumaPageMask;
ULONG HalpFakeNumaPageShift;
ULONG
HalpFakeNumaQueryPageToNode(
IN ULONG_PTR PhysicalPageNumber
)
{
ULONG Node;
Node = (ULONG)PhysicalPageNumber >> HalpFakeNumaPageShift;
Node &= HalpFakeNumaPageMask;
return Node;
}
NTSTATUS
HalpFakeNumaQueryProcessorNode(
IN ULONG ProcessorNumber,
OUT PUSHORT ProcessorId,
OUT PUCHAR NodeNumber
)
{
NTSTATUS Status;
KAFFINITY ProcessorMask;
KAFFINITY Mask;
UCHAR Node;
USHORT ApicId;
#if defined(APIC_HAL) && !defined(NT_UP)
Status = HalpGetApicIdByProcessorNumber((UCHAR)ProcessorNumber, &ApicId);
if (!NT_SUCCESS(Status)) {
return Status;
}
*ProcessorId = ApicId;
#else
*ProcessorId = (USHORT)ProcessorNumber;
Status = STATUS_SUCCESS;
#endif
ProcessorMask = 1 << ProcessorNumber;
for (Node = 0; Node < HalpFakeNumaNodes; Node++) {
Mask = HalpFakeNumaAffinity << (Node * HalpFakeNumaAffinityShift);
if ((Mask & ProcessorMask) != 0) {
*NodeNumber = Node;
break;
}
}
return Status;
}
#endif
NTSTATUS
HaliQuerySystemInformation(
IN HAL_QUERY_INFORMATION_CLASS InformationClass,
IN ULONG BufferSize,
OUT PVOID Buffer,
OUT PULONG ReturnedLength
)
{
NTSTATUS Status;
PVOID InternalBuffer;
ULONG Length;
union {
HAL_POWER_INFORMATION PowerInf;
HAL_PROCESSOR_SPEED_INFORMATION ProcessorInf;
MCA_EXCEPTION McaException;
HAL_DISPLAY_BIOS_INFORMATION DisplayBiosInf;
} U;
BOOLEAN bUseFrameBufferCaching;
PAGED_CODE();
Status = STATUS_SUCCESS;
*ReturnedLength = 0;
Length = 0;
switch (InformationClass) {
#ifndef ACPI_HAL
case HalInstalledBusInformation:
Status = HalpQueryInstalledBusInformation (
Buffer,
BufferSize,
ReturnedLength
);
break;
#endif
case HalFrameBufferCachingInformation:
// Note - we want to return TRUE here to enable USWC in all
// cases except in a "Shared Memory Cluster" machine.
bUseFrameBufferCaching = TRUE;
InternalBuffer = &bUseFrameBufferCaching;
Length = sizeof (BOOLEAN);
break;
case HalMcaLogInformation:
InternalBuffer = &U.McaException;
Status = HalpGetMcaLog ((PMCA_EXCEPTION)Buffer,
BufferSize,
ReturnedLength);
break;
#if !defined(_WIN64)
case HalDisplayBiosInformation:
InternalBuffer = &U.DisplayBiosInf;
Length = sizeof(U.DisplayBiosInf);
U.DisplayBiosInf = HalpGetDisplayBiosInformation ();
break;
#endif
#ifdef _PNP_POWER_
case HalPowerInformation:
RtlZeroMemory (&U.PowerInf, sizeof(HAL_POWER_INFORMATION));
InternalBuffer = &U.PowerInf;
Length = sizeof (HAL_POWER_INFORMATION);
break;
case HalProcessorSpeedInformation:
RtlZeroMemory (&U.ProcessorInf, sizeof(HAL_POWER_INFORMATION));
U.ProcessorInf.MaximumProcessorSpeed = 100;
U.ProcessorInf.CurrentAvailableSpeed = 100;
U.ProcessorInf.ConfiguredSpeedLimit = 100;
InternalBuffer = &U.PowerInf;
Length = sizeof (HAL_PROCESSOR_SPEED_INFORMATION);
break;
case HalCallbackInformation:
InternalBuffer = &HalCallback;
Length = sizeof (HAL_CALLBACKS);
break;
#endif
#if defined(_HALPAE_) && !defined(NT_UP)
case HalNumaTopologyInterface:
if ((BufferSize == sizeof(HAL_NUMA_TOPOLOGY_INTERFACE)) &&
(HalPaeEnabled() == TRUE)) {
Status = STATUS_INVALID_LEVEL;
#if defined(ACPI_HAL)
if (HalpAcpiSrat) {
Status = HalpGetAcpiStaticNumaTopology(Buffer);
if (NT_SUCCESS(Status)) {
*ReturnedLength = sizeof(HAL_NUMA_TOPOLOGY_INTERFACE);
}
break;
}
#endif
//
// Mega Kludge:
//
// Testing Testing Testing. MM may supply a
// fake NUMA configuration for testing purposes.
// In this case information is passed IN to the
// HAL using this query only interface by passing
// information in the output buffer and in the
// returned length field.
//
// The returned length field will have been
// initialized to the special value 'NUMA', in
// this case, the incoming information buffer
// contains the NUMA configuration.
//
if (HalpFakeNumaNodes == 0) {
struct {
ULONG Nodes:3;
ULONG AffinityShift:6;
ULONG PageShift:6;
ULONG Signature:17;
ULONG Affinity;
ULONG Mask;
} Fake;
ULONG ValidateNodes;
ULONG ValidateAffinity1;
ULONG ValidateAffinity2;
RtlCopyMemory(&Fake, Buffer, sizeof(Fake));
//
// Do a little validation.
//
if ((Fake.Signature != 0x15a5a) ||
(Fake.Nodes == 0) ||
((Fake.AffinityShift | Fake.PageShift) & 0x20) ||
(Fake.Affinity == 0) ||
(Fake.Mask == 0) ||
(Fake.Mask >= Fake.Nodes)) {
Status = STATUS_INVALID_LEVEL;
break;
}
HalpFakeNumaAffinity = Fake.Affinity;
HalpFakeNumaAffinityShift = Fake.AffinityShift;
HalpFakeNumaPageMask = Fake.Mask;
HalpFakeNumaPageShift = Fake.PageShift;
//
// Generate the affinity mask for each node and
// make sure there's no overlapping affinity masks.
//
ValidateNodes = Fake.Nodes;
ValidateAffinity1 = 0;
ValidateAffinity2 = 0;
while (ValidateNodes) {
ValidateNodes--;
ValidateAffinity1 = HalpFakeNumaAffinity <<
(HalpFakeNumaAffinityShift * ValidateNodes);
if (ValidateAffinity1 == 0) {
break;
}
if ((ValidateAffinity1 & ValidateAffinity2) != 0) {
ValidateAffinity1 = 0;
break;
}
ValidateAffinity2 |= ValidateAffinity1;
}
if (!ValidateAffinity1) {
Status = STATUS_INVALID_LEVEL;
break;
}
HalpFakeNumaNodes = Fake.Nodes;
}
//
// End Mega Kludge.
//
if ((HalPaeEnabled() == TRUE) &&
(HalpFakeNumaNodes != 0) &&
(HalpFakeNumaAffinity != 0) &&
(HalpFakeNumaAffinityShift != 0) &&
(HalpFakeNumaPageMask != 0) &&
(HalpFakeNumaPageShift != 0) ) {
//
// Pretend we have a numa configuration,...
// for testing purposes only.
//
HAL_NUMA_TOPOLOGY_INTERFACE * NumaInfo;
NumaInfo = (HAL_NUMA_TOPOLOGY_INTERFACE *)Buffer;
NumaInfo->NumberOfNodes = HalpFakeNumaNodes;
NumaInfo->QueryProcessorNode = HalpFakeNumaQueryProcessorNode;
NumaInfo->PageToNode = HalpFakeNumaQueryPageToNode;
*ReturnedLength = sizeof(HAL_NUMA_TOPOLOGY_INTERFACE);
Status = STATUS_SUCCESS;
}
} else {
//
// Buffer size is wrong, we could return valid data
// if the buffer is too big,.... but instead we will
// use this as an indication that we're not compatible
// with the kernel.
//
Status = STATUS_INFO_LENGTH_MISMATCH;
}
break;
#endif
case HalQueryMcaInterface:
if (BufferSize == sizeof(HAL_MCA_INTERFACE)) {
HAL_MCA_INTERFACE *McaInterface;
McaInterface = (HAL_MCA_INTERFACE *)Buffer;
McaInterface->Lock = HalpMcaLockInterface;
McaInterface->Unlock = HalpMcaUnlockInterface;
McaInterface->ReadRegister = HalpMcaReadRegisterInterface;
*ReturnedLength = sizeof(HAL_MCA_INTERFACE);
Status = STATUS_SUCCESS;
} else {
Status = STATUS_INFO_LENGTH_MISMATCH;
}
break;
case HalQueryMaxHotPlugMemoryAddress:
if (BufferSize == sizeof(PHYSICAL_ADDRESS)) {
#ifdef ACPI_HAL
*((PPHYSICAL_ADDRESS) Buffer) = HalpMaxHotPlugMemoryAddress;
*ReturnedLength = sizeof(PHYSICAL_ADDRESS);
Status = STATUS_SUCCESS;
#else
Status = STATUS_NOT_IMPLEMENTED;
#endif
} else {
Status = STATUS_INFO_LENGTH_MISMATCH;
}
break;
case HalQueryAMLIIllegalIOPortAddresses:
{
HAL_AMLI_BAD_IO_ADDRESS_LIST BadIOAddrList[] =
{
{0x000, 0x10, 0x1, NULL }, // ISA DMA
{0x020, 0x2, 0x0, NULL }, // PIC
{0x040, 0x4, 0x1, NULL }, // Timer1, Referesh, Speaker, Control Word
{0x048, 0x4, 0x1, NULL }, // Timer2, Failsafe
{0x070, 0x2, 0x1, NULL }, // Cmos/NMI enable
{0x074, 0x3, 0x1, NULL }, // Extended Cmos
{0x081, 0x3, 0x1, NULL }, // DMA
{0x087, 0x1, 0x1, NULL }, // DMA
{0x089, 0x1, 0x1, NULL }, // DMA
{0x08a, 0x2, 0x1, NULL }, // DMA
{0x08f, 0x1, 0x1, NULL }, // DMA
{0x090, 0x2, 0x1, NULL }, // Arbritration Control Port, Card Select Feedback
{0x093, 0x2, 0x1, NULL }, // Reserved, System board setup
{0x096, 0x2, 0x1, NULL }, // POS channel select
{0x0A0, 0x2, 0x0, NULL }, // Cascaded PIC
{0x0C0, 0x20, 0x1, NULL }, // ISA DMA
{0x4D0, 0x2, 0x0, NULL }, // Edge, level control registers for PIC
{0xCF8, 0x8, 0x1, &HaliHandlePCIConfigSpaceAccess}, // PCI Config Space Access Pair
{0x0, 0x0, 0x0, NULL }
};
if(BufferSize < sizeof(BadIOAddrList))
{
*ReturnedLength = sizeof(BadIOAddrList);
Status = STATUS_INFO_LENGTH_MISMATCH;
}
else
{
Length = sizeof(BadIOAddrList);
InternalBuffer = BadIOAddrList;
Status = STATUS_SUCCESS;
}
break;
}
default:
Status = STATUS_INVALID_LEVEL;
break;
}
//
// If non-zero Length copy data to callers buffer
//
if (Length) {
if (BufferSize < Length) {
Length = BufferSize;
}
*ReturnedLength = Length;
RtlCopyMemory (Buffer, InternalBuffer, Length);
}
return Status;
}
NTSTATUS
HaliSetSystemInformation (
IN HAL_SET_INFORMATION_CLASS InformationClass,
IN ULONG BufferSize,
IN PVOID Buffer
)
{
NTSTATUS Status;
PAGED_CODE();
Status = STATUS_SUCCESS;
switch (InformationClass) {
case HalMcaRegisterDriver:
Status = HalpMcaRegisterDriver(
(PMCA_DRIVER_INFO) Buffer // Info about registering driver
);
break;
default:
Status = STATUS_INVALID_LEVEL;
break;
}
return Status;
}
#ifdef _PNP_POWER_
VOID
HalpLockSuspendCode (
IN PVOID CallbackContext,
IN PVOID Argument1,
IN PVOID Argument2
)
{
static PVOID CodeLock;
switch ((ULONG) Argument1) {
case 0:
//
// Lock code down which might be needed to perform a suspend
//
ASSERT (CodeLock == NULL);
CodeLock = MmLockPagableCodeSection (&HaliSuspendHibernateSystem);
break;
case 1:
//
// Release the code lock
//
MmUnlockPagableImageSection (CodeLock);
CodeLock = NULL;
break;
}
}
#endif
/*** HaliHandlePCIConfigSpaceAccess - Check to see if the Firmware is attempting to
* access to PCI Config space. If so, intercept
* the read/write call and do it using HAL API's.
* This way we can make these calls sync.
*
* ENTRY
* BOOLEAN Read - TRUE iff read
* ULONG Addr - Address to do the operation on
* ULONG Size - Size of data
* PULONG pData - Pointer to the data buffer.
*
* EXIT
* STATUS_SUCCESS if we do the PCI config space access.
*/
NTSTATUS HaliHandlePCIConfigSpaceAccess( BOOLEAN Read,
ULONG Addr,
ULONG Size,
PULONG pData
)
{
static PCI_TYPE1_CFG_BITS CF8_Data = {0};
static BOOLEAN CF8_Called = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
if(Addr == 0xCF8)
{
CF8_Data.u.AsULONG = *pData;
CF8_Called = TRUE;
}
else if(Addr >= 0xCFC && Addr <= 0xCFF)
{
if(CF8_Called)
{
ULONG Offset = 0;
ULONG Return = 0;
PCI_SLOT_NUMBER SlotNumber = {0};
Offset = (CF8_Data.u.bits.RegisterNumber << 2) + (Addr - 0xCFC);
SlotNumber.u.bits.FunctionNumber = CF8_Data.u.bits.FunctionNumber;
SlotNumber.u.bits.DeviceNumber = CF8_Data.u.bits.DeviceNumber;
if (Read)
{
//
// Do PCI config space read through HAL
//
Return = HaliPciInterfaceReadConfig( NULL,
(UCHAR)CF8_Data.u.bits.BusNumber,
SlotNumber.u.AsULONG,
pData,
Offset,
Size
);
}
else
{
//
// Do PCI config space write through HAL
//
Return = HaliPciInterfaceWriteConfig( NULL,
(UCHAR)CF8_Data.u.bits.BusNumber,
SlotNumber.u.AsULONG,
pData,
Offset,
Size
);
}
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
return Status;
}