/*++ Copyright (c) 1991 Microsoft Corporation Module Name: ixinfo.c Abstract: Author: Ken Reneris (kenr) 08-Aug-1994 Environment: Kernel mode only. Revision History: --*/ #include "halp.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE,HaliQuerySystemInformation) #pragma alloc_text(PAGE,HaliSetSystemInformation) #pragma alloc_text(INIT,HalInitSystemPhase2) #endif // // NUMA Information. // extern PVOID HalpAcpiSrat; NTSTATUS HalpGetAcpiStaticNumaTopology( HAL_NUMA_TOPOLOGY_INTERFACE * NumaInfo ); NTSTATUS HalpGenerateCMCInterrupt( VOID ); NTSTATUS HaliQuerySystemInformation( IN HAL_QUERY_INFORMATION_CLASS InformationClass, IN ULONG BufferSize, OUT PVOID Buffer, OUT PULONG ReturnedLength ) { NTSTATUS Status; PVOID InternalBuffer; ULONG Length, PlatformProperties; union { HAL_POWER_INFORMATION PowerInf; HAL_PROCESSOR_SPEED_INFORMATION ProcessorInf; HAL_ERROR_INFO ErrorInfo; HAL_DISPLAY_BIOS_INFORMATION DisplayBiosInf; HAL_PLATFORM_INFORMATION PlatformInfo; } U; BOOLEAN bUseFrameBufferCaching; PAGED_CODE(); Status = STATUS_SUCCESS; *ReturnedLength = 0; Length = 0; switch (InformationClass) { case HalFrameBufferCachingInformation: Status = HalpGetPlatformProperties(&PlatformProperties); if (NT_SUCCESS(Status) && (PlatformProperties & HAL_PLATFORM_DISABLE_WRITE_COMBINING)) { if ( PlatformProperties & HAL_PLATFORM_ENABLE_WRITE_COMBINING_MMIO ) { bUseFrameBufferCaching = TRUE; } else { bUseFrameBufferCaching = FALSE; } } else { // // Note - we want to return TRUE here to enable USWC in all // cases except in a "Shared Memory Cluster" machine. // Status = STATUS_SUCCESS; bUseFrameBufferCaching = TRUE; } InternalBuffer = &bUseFrameBufferCaching; Length = sizeof (BOOLEAN); break; case HalMcaLogInformation: Status = HalpGetMcaLog( Buffer, BufferSize, ReturnedLength ); break; case HalCmcLogInformation: Status = HalpGetCmcLog( Buffer, BufferSize, ReturnedLength ); break; case HalCpeLogInformation: Status = HalpGetCpeLog( Buffer, BufferSize, ReturnedLength ); break; case HalErrorInformation: InternalBuffer = &U.ErrorInfo; if ( Buffer && (BufferSize > sizeof(U.ErrorInfo.Version)) ) { U.ErrorInfo.Version = ((PHAL_ERROR_INFO)Buffer)->Version; Status = HalpGetMceInformation(&U.ErrorInfo, &Length); } else { Status = STATUS_INVALID_PARAMETER; } break; case HalDisplayBiosInformation: InternalBuffer = &U.DisplayBiosInf; Length = sizeof(U.DisplayBiosInf); U.DisplayBiosInf = HalpGetDisplayBiosInformation (); break; case HalProcessorSpeedInformation: RtlZeroMemory (&U.ProcessorInf, sizeof(HAL_PROCESSOR_SPEED_INFORMATION)); // U.ProcessorInf.MaximumProcessorSpeed = HalpCPUMHz; // U.ProcessorInf.CurrentAvailableSpeed = HalpCPUMHz; // U.ProcessorInf.ConfiguredSpeedLimit = HalpCPUMHz; U.ProcessorInf.ProcessorSpeed = HalpCPUMHz; InternalBuffer = &U.ProcessorInf; Length = sizeof (HAL_PROCESSOR_SPEED_INFORMATION); break; case HalProfileSourceInformation: Status = HalpProfileSourceInformation ( Buffer, BufferSize, ReturnedLength); return Status; break; case HalNumaTopologyInterface: if (BufferSize == sizeof(HAL_NUMA_TOPOLOGY_INTERFACE)) { Status = STATUS_INVALID_LEVEL; if (HalpAcpiSrat) { Status = HalpGetAcpiStaticNumaTopology(Buffer); if (NT_SUCCESS(Status)) { *ReturnedLength = sizeof(HAL_NUMA_TOPOLOGY_INTERFACE); } break; } } 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; case HalPartitionIpiInterface: // // Some platforms generate interrupts in remote partitions // as part of their shared memory implementation. This is // accomplished by targetting an IPI at a processor/vector // in that remote partition. Provide interfaces to enable // this but make them conditional on presence of IPPT // table and appropriate bit explicitly enabling this // functionality. OEM is responsible for ensuring that an // interrupt isn't sent to a logical processor that isn't // present. // if (BufferSize >= sizeof(HAL_CROSS_PARTITION_IPI_INTERFACE)) { Status = HalpGetPlatformProperties(&PlatformProperties); if (NT_SUCCESS(Status) && (PlatformProperties & IPPT_ENABLE_CROSS_PARTITION_IPI)) { Status = HalpGetCrossPartitionIpiInterface(Buffer); if (NT_SUCCESS(Status)) { *ReturnedLength = sizeof(HAL_CROSS_PARTITION_IPI_INTERFACE); } } else { Status = STATUS_UNSUCCESSFUL; } } else { Status = STATUS_INFO_LENGTH_MISMATCH; } break; case HalPlatformInformation: // // Any platform information that must be exposed to the kernel. // if (BufferSize >= sizeof(HAL_PLATFORM_INFORMATION)) { Status = HalpGetPlatformProperties(&PlatformProperties); if (NT_SUCCESS(Status)) { InternalBuffer = &U.PlatformInfo; Length = sizeof(U.PlatformInfo); U.PlatformInfo.PlatformFlags = PlatformProperties; } } else { Status = STATUS_INFO_LENGTH_MISMATCH; } 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; } // HaliQuerySystemInformation() // BOOLEAN // HalpIsFunctionPointerValid( // PVOID Va // ) // // Return TRUE if Function Pointer and Function are valid. // Return TRUE if Function Pointer is valid and Function is NULL. // Return FALSE if Function Pointer is invalid or Function is not NULL but invalid. // #define HalpIsFunctionPointerValid( _Va ) ( MmIsAddressValid((PVOID)(_Va)) && ((*((PULONG_PTR)(_Va)) == 0) || MmIsAddressValid( *((PVOID *)(_Va)) ))) NTSTATUS HaliSetSystemInformation ( IN HAL_SET_INFORMATION_CLASS InformationClass, IN ULONG BufferSize, IN PVOID Buffer ) /*++ Routine Description: The function allows setting of various fields return by HalQuerySystemInformation. Arguments: InformationClass - Information class of the request. BufferSize - Size of buffer supplied by the caller. Buffer - Supplies the data to be set. Return Value: STATUS_SUCCESS or error. --*/ { NTSTATUS Status; PAGED_CODE(); Status = STATUS_SUCCESS; switch (InformationClass) { case HalProfileSourceInterval: if (BufferSize == sizeof(HAL_PROFILE_SOURCE_INTERVAL)) { PHAL_PROFILE_SOURCE_INTERVAL sourceInterval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer; Status = HalSetProfileSourceInterval( sourceInterval->Source, &sourceInterval->Interval ); } else { Status = STATUS_INFO_LENGTH_MISMATCH; } break; case HalProfileSourceInterruptHandler: // // Register an Profiling Interrupt Handler. // Status = STATUS_INFO_LENGTH_MISMATCH; if (BufferSize == sizeof(ULONG_PTR)) { if ( !(HalpFeatureBits & HAL_PERF_EVENTS) ) { Status = STATUS_NO_SUCH_DEVICE; } else if ( !HalpIsFunctionPointerValid(Buffer) ) { Status = STATUS_INVALID_ADDRESS; } else { Status = (NTSTATUS)KiIpiGenericCall( HalpSetProfileInterruptHandler, *(PULONG_PTR)Buffer ); } } break; case HalKernelErrorHandler: Status = HalpMceRegisterKernelDriver( (PKERNEL_ERROR_HANDLER_INFO) Buffer, BufferSize ); break; case HalMcaRegisterDriver: Status = HalpMcaRegisterDriver( (PMCA_DRIVER_INFO) Buffer // Info about registering driver ); break; case HalCmcRegisterDriver: Status = HalpCmcRegisterDriver( (PCMC_DRIVER_INFO) Buffer // Info about registering driver ); break; case HalCpeRegisterDriver: Status = HalpCpeRegisterDriver( (PCPE_DRIVER_INFO) Buffer // Info about registering driver ); break; case HalMcaLog: // Class requested by MS Machine Check Event Test Team. Status = HalpSetMcaLog( (PMCA_EXCEPTION) Buffer, BufferSize ); break; case HalCmcLog: // Class requested by MS Machine Check Event Test Team. Status = HalpSetCmcLog( (PCMC_EXCEPTION) Buffer, BufferSize ); break; case HalCpeLog: // Class requested by MS Machine Check Event Test Team. Status = HalpSetCpeLog( (PCPE_EXCEPTION) Buffer, BufferSize ); break; case HalGenerateCmcInterrupt: Status = HalpGenerateCMCInterrupt(); break; default: Status = STATUS_INVALID_LEVEL; break; } return Status; } // HaliSetSystemInformation()