/*++ Copyright (c) 1997 Microsoft Corporation Module Name: pmsapic.c Abstract: Implements various SAPIC-ACPI functions. Author: Todd Kjos (Hewlett-Packard) 20-Apr-1998 Based on I386 version of pmapic.c: Jake Oshins (jakeo) 19-May-1997 Environment: Kernel mode only. Revision History: --*/ #include "halp.h" #include "acpitabl.h" #include "iosapic.h" #include "xxacpi.h" #include "ixsleep.h" PMAPIC HalpApicTable; struct _IOAPIC_DEBUG_TABLE { PIO_INTR_CONTROL IoIntrControl; PIO_SAPIC_REGS IoSapicRegs; } *HalpApicDebugAddresses; ULONG DetectAcpiMP( OUT PBOOLEAN IsConfiguredMp, IN PLOADER_PARAMETER_BLOCK LoaderBlock ); VOID HalpInitMPInfo( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PMAPIC ApicTable ); BOOLEAN HalpVerifyIoSapic( IN PUCHAR BaseAddress ); VOID HalpSaveInterruptControllerState( VOID ); VOID HalpRestoreInterruptControllerState( VOID ); VOID HalpSetInterruptControllerWakeupState( ULONG Context ); VOID HalpSetCPEVectorState( IN ULONG GlobalInterrupt, IN UCHAR SapicVector, IN USHORT DestinationCPU, IN ULONG Flags ); VOID HalpProcessLocalSapic( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PPROCLOCALSAPIC ProcLocalSapic ); VOID HalpProcessIoSapic( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PIOSAPIC IoSapic ); VOID HalpProcessIsaVector( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PISA_VECTOR IsaVector ); VOID HalpProcessPlatformInt( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PPLATFORM_INTERRUPT PlatformInt ); extern UCHAR rgzNoApicTable[]; extern UCHAR rgzNoApic[]; extern UCHAR rgzApicNotVerified[]; extern ULONG HalpPicVectorRedirect[]; struct _MPINFO HalpMpInfo; extern ULONG HalpPicVectorFlags[]; extern ULONG HalpIpiClock; extern BOOLEAN HalpHiberInProgress; // from pmdata.c: CPE related. extern ULONG HalpCPEIntIn[]; extern USHORT HalpCPEDestination[]; extern ULONG HalpCPEVectorFlags[]; extern UCHAR HalpCPEIoSapicVector[]; extern ULONG HalpMaxCPEImplemented; BOOLEAN HalpPicStateIntact = TRUE; PIO_INTR_CONTROL HalpIoSapicList = NULL; #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, DetectAcpiMP) #pragma alloc_text(INIT, HalpInitMPInfo) #pragma alloc_text(INIT, HalpProcessLocalSapic) #pragma alloc_text(INIT, HalpProcessIoSapic) #pragma alloc_text(INIT, HalpProcessIsaVector) #pragma alloc_text(INIT, HalpProcessPlatformInt) #pragma alloc_text(PAGELK, HalpVerifyIoSapic) #pragma alloc_text(PAGELK, HalpSaveInterruptControllerState) #pragma alloc_text(PAGELK, HalpRestoreInterruptControllerState) #pragma alloc_text(PAGELK, HalpSetInterruptControllerWakeupState) #pragma alloc_text(PAGELK, HalpAcpiPicStateIntact) #endif ULONG DetectAcpiMP( OUT PBOOLEAN IsConfiguredMp, IN PLOADER_PARAMETER_BLOCK LoaderBlock ) { UCHAR ApicVersion, index, processorNumber; PUCHAR LocalApic; NTSTATUS status; // // Make sure there is an SAPIC Table // HalpApicTable = HalpGetAcpiTablePhase0(LoaderBlock, APIC_SIGNATURE); if (HalpApicTable == NULL) { HalDisplayString(rgzNoApicTable); KeBugCheckEx(ACPI_BIOS_ERROR, 0x11, 10, 0, 0); return(FALSE); } HalDebugPrint(( HAL_INFO, "HAL: Found a MADT table at %p\n", HalpApicTable )); HalDebugPrint(( HAL_INFO, "HAL: Signature: %x Length: %x\n", HalpApicTable->Header.Signature, HalpApicTable->Header.Length )); HalDebugPrint(( HAL_INFO, "HAL: OEMID: %s\n", HalpApicTable->Header.OEMID )); // We have a SAPIC table. Initialize the interrupt info structure HalpInitMPInfo(LoaderBlock, HalpApicTable); if (HalpMpInfo.IoSapicCount == 0) { // // There are no IO Sapics. // // Should we allow this case on the theory that // that all the interrupts are connected to LINTx pins on the CPU? // HalDebugPrint(( HAL_ERROR, rgzNoApic )); return (FALSE); } if (HalpMpInfo.ProcessorCount == 0) { KeBugCheckEx(ACPI_BIOS_ERROR, 0x11, 11, 0, 0); } // // Initialize NtProcessorNumber in the order that we are going to process // them in HalStartNextProcessor. The BSP is 0 and the rest are numbered // in the order the Local SAPICs appear in the MADT starting at 1. // processorNumber = 1; for (index = 0; index < HalpMpInfo.ProcessorCount; index++) { if (HalpProcessorInfo[index].LocalApicID == (USHORT)PCR->HalReserved[PROCESSOR_ID_INDEX]) { HalpProcessorInfo[index].NtProcessorNumber = 0; } else { HalpProcessorInfo[index].NtProcessorNumber = processorNumber++; } } *IsConfiguredMp = (HalpMpInfo.ProcessorCount > 1 ? TRUE : FALSE); return TRUE; } #define IO_SAPIC_REGS_SIZE 4096 VOID HalpInitMPInfo( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PMAPIC ApicTable ) /*++ Routine Description: This routine initializes a HAL specific data structure that is used by the HAL to simplify access to MP information. Arguments: SapicTable Pointer to the SAPIC table. Return Value: None */ { PAPICTABLE TablePtr; ULONG i; HalpMpInfo.ProcessorCount = 0; HalpMpInfo.IoSapicCount = 0; // Walk the Multiple Apic table... TablePtr = (PAPICTABLE) ApicTable->APICTables; // Loop ends when TraversePtr is off the end of the table... while ((UINT_PTR)TablePtr < ((UINT_PTR)ApicTable + ApicTable->Header.Length)) { if (TablePtr->Type == LOCAL_SAPIC) { HalpProcessLocalSapic(LoaderBlock, (PPROCLOCALSAPIC)TablePtr); } else if (TablePtr->Type == IO_SAPIC) { HalpProcessIoSapic(LoaderBlock, (PIOSAPIC)TablePtr); } else if (TablePtr->Type == ISA_VECTOR_OVERRIDE) { HalpProcessIsaVector(LoaderBlock, (PISA_VECTOR)TablePtr); } else if (TablePtr->Type == PLATFORM_INTERRUPT_SOURCE) { HalpProcessPlatformInt(LoaderBlock, (PPLATFORM_INTERRUPT)TablePtr); } else { HalDebugPrint(( HAL_ERROR, "HAL: Processing MADT - Skip Table %p: Type = %d, Length = %d\n", TablePtr, TablePtr->Type, TablePtr->Length )); } (UINT_PTR)TablePtr += TablePtr->Length; } // // Check if there is Interrupt Source Override entry. If there is, force the // new flags into the SAPIC state. This is done now because of the possibility // the firmware can place the ISO Vector Override entry ahead of IOSAPIC entry. // for (i = 0; i < PIC_VECTORS; i++) { if (HalpPicVectorFlags[i]) { HaliSetVectorState( HalpPicVectorRedirect[i], HalpPicVectorFlags[i] ); } } } VOID HalpProcessLocalSapic( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PPROCLOCALSAPIC ProcLocalSapic ) { USHORT LID; ULONG ProcessorNum; if (ProcLocalSapic->Length != PROCESSOR_LOCAL_SAPIC_LENGTH) { HalDebugPrint(( HAL_ERROR, "HAL: HalpProcessLocalSapic - Invalid Length %p: Expected %d, Found %d\n", ProcLocalSapic, PROCESSOR_LOCAL_SAPIC_LENGTH, ProcLocalSapic->Length )); return; } // Make sure processor is enabled... if (!(ProcLocalSapic->Flags & PLAF_ENABLED)) { return; } // It is. Bump the count and store the LID value for IPIs LID = (ProcLocalSapic->APICID << 8) | ProcLocalSapic->APICEID; HalpProcessorInfo[HalpMpInfo.ProcessorCount].AcpiProcessorID = ProcLocalSapic->ACPIProcessorID; HalpProcessorInfo[HalpMpInfo.ProcessorCount].LocalApicID = LID; HalpMpInfo.ProcessorCount++; HalDebugPrint(( HAL_INFO, "HAL: Found a processor-local SAPIC: %p LID=%x\n", ProcLocalSapic, LID )); } VOID HalpProcessIoSapic( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PIOSAPIC IoSapic ) { ULONG IntiBase,RedirEntries; PHYSICAL_ADDRESS IoSapicPhys; PVOID IoSapicBase; UINT_PTR IoSapicPhysBase; PIO_SAPIC_REGS SapicRegs; PIO_INTR_CONTROL IoIntrControl; ULONG i; union { ULONG raw; SAPIC_VERSION version; } versionUnion; if (IoSapic->Length != IO_SAPIC_LENGTH) { HalDebugPrint(( HAL_ERROR, "HAL: HalpProcessIoSapic - Invalid Length %p: Expected %d, Found %d\n", IoSapic, IO_SAPIC_LENGTH, IoSapic->Length )); return; } HalDebugPrint(( HAL_INFO, "HAL: Found an IO SAPIC: %p\n", IoSapic )); // Map IO Sapic Registers... IntiBase = IoSapic->SystemVectorBase; IoSapicPhysBase = IoSapic->IOSAPICAddress; IoSapicPhys.QuadPart = (UINT_PTR)IoSapicPhysBase; IoSapicBase = HalpMapPhysicalMemory( IoSapicPhys, ADDRESS_AND_SIZE_TO_SPAN_PAGES(IoSapicPhys.LowPart, IO_SAPIC_REGS_SIZE), MmNonCached); ASSERT(IoSapicBase); SapicRegs = (PIO_SAPIC_REGS)IoSapicBase; if (!SapicRegs) { HalDebugPrint(( HAL_ERROR, "HAL: Couldn't map the I/O Sapic\n" )); return; } // Read the IO Sapic version and extract the number of redirection table entries SapicRegs->RegisterSelect = IO_VERS_REGISTER; SapicRegs->RegisterWindow = 0; versionUnion.raw = SapicRegs->RegisterWindow; // // CPQMOD_JL001 - Incorrect count - hw provide max rte index not // count. // //RedirEntries = versionUnion.version.MaxRedirEntries; RedirEntries = versionUnion.version.MaxRedirEntries + 1; if (HalpVerifyIoSapic((PUCHAR)SapicRegs)) { // Allocate and fill out a IO Sapic structure PHYSICAL_ADDRESS physicalAddress; physicalAddress.QuadPart = (LONGLONG)HalpAllocPhysicalMemory( LoaderBlock, ~0, BYTES_TO_PAGES(sizeof(IO_INTR_CONTROL) + (RedirEntries*sizeof(IOSAPICINTI))), FALSE ); if (physicalAddress.QuadPart == 0) { HalDebugPrint(( HAL_ERROR, "HAL: Couldn't allocate memory for the IO Sapic structures\n" )); return; } IoIntrControl = (PIO_INTR_CONTROL)HalpMapPhysicalMemory( physicalAddress, ADDRESS_AND_SIZE_TO_SPAN_PAGES(physicalAddress.LowPart, sizeof(IO_INTR_CONTROL) + (RedirEntries*sizeof(IOSAPICINTI))), MmCached ); ASSERT(IoIntrControl); IoIntrControl->IntiBase = IntiBase; IoIntrControl->IntiMax = IntiBase + RedirEntries - 1; IoIntrControl->RegBaseVirtual = IoSapicBase; IoIntrControl->RegBasePhysical = IoSapicPhys; IoIntrControl->IntrMethods = &HalpIoSapicMethods; IoIntrControl->InterruptAffinity = 0xffffffff; IoIntrControl->NextCpu = 0; IoIntrControl->flink = NULL; for (i = 0; i < RedirEntries; i++) { IoIntrControl->Inti[i].Vector = DELIVER_FIXED | ACTIVE_LOW | LEVEL_TRIGGERED; IoIntrControl->Inti[i].Destination = 0; IoIntrControl->Inti[i].GlobalVector = 0; // // CPQMOD_JL002 - Fix for using the rte and not the // SystemVector. // //IoIntrControl->IntrMethods->MaskEntry(IoIntrControl,IntiBase+i); IoIntrControl->IntrMethods->MaskEntry(IoIntrControl,i); } // Insert structure into list. Since we are running on P0 at // Phase0 initialization, we can assume that no one else is // modifying this list therefore no synchronization is needed. if (HalpIoSapicList == NULL) { HalpIoSapicList = IoIntrControl; } else { PIO_INTR_CONTROL *LastLink; PIO_INTR_CONTROL IoSapicListEntry; LastLink = &HalpIoSapicList; IoSapicListEntry = HalpIoSapicList; while (IoSapicListEntry != NULL) { if (IoSapicListEntry->IntiBase > IoIntrControl->IntiMax) { // Insert new entry before current entry IoIntrControl->flink = *LastLink; *LastLink = IoIntrControl; break; } else { LastLink = &IoSapicListEntry->flink; IoSapicListEntry = IoSapicListEntry->flink; } } if (IoSapicListEntry == NULL) { // We got to the end of the list. The new entry goes // after the last entry... *LastLink = IoIntrControl; } } HalpMpInfo.IoSapicCount++; } else { // The Io Sapic is not there, ignore this entry in the table HalDebugPrint(( HAL_ERROR, rgzApicNotVerified )); HalpUnmapVirtualAddress(IoSapicBase, ADDRESS_AND_SIZE_TO_SPAN_PAGES(IoSapicBase, IO_SAPIC_REGS_SIZE)); } } VOID HalpProcessIsaVector( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PISA_VECTOR IsaVector ) { if (IsaVector->Length != ISA_VECTOR_OVERRIDE_LENGTH) { HalDebugPrint(( HAL_ERROR, "HAL: HalpProcessIsaVector - Invalid Length %p: Expected %d, Found %d\n", IsaVector, ISA_VECTOR_OVERRIDE_LENGTH, IsaVector->Length )); return; } // // Found an ISA vector redirection entry. // HalpPicVectorRedirect[IsaVector->Source] = IsaVector->GlobalSystemInterruptVector; HalpPicVectorFlags[IsaVector->Source] = IsaVector->Flags; HalDebugPrint(( HAL_INFO, "HAL: Found an ISA VECTOR: %p, %x -> %x, flags: %x\n", IsaVector, IsaVector->Source, IsaVector->GlobalSystemInterruptVector, IsaVector->Flags )); } VOID HalpProcessPlatformInt( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN PPLATFORM_INTERRUPT PlatformInt ) { static ULONG currentCPECount = 0; if (PlatformInt->Length != PLATFORM_INTERRUPT_SOURCE_LENGTH) { HalDebugPrint(( HAL_ERROR, "HAL: HalpProcessPlatformInt - Invalid Length %p: Expected %d, Found %d\n", PlatformInt, PLATFORM_INTERRUPT_SOURCE_LENGTH, PlatformInt->Length )); return; } // // Process a Corrected Platform Error Interrupt Source structure. // if (PlatformInt->InterruptType == PLATFORM_INT_CPE) { // // Does this platform has more (than what we expected) number of CPE sources? // if ( currentCPECount >= HALP_CPE_MAX_INTERRUPT_SOURCES ) { HalDebugPrint(( HAL_ERROR, "HAL: Platform Interrupt Source %p skipped due to overflow: %ld >= HALP_CPE_MAX_INTERRUPT_SOURCES\n", PlatformInt, currentCPECount )); return; } // // Save the input pin number of SAPIC for this CPE source // HalpCPEIntIn[currentCPECount] = (ULONG)PlatformInt->GlobalVector; // // Save the Flags for this CPE source // HalpCPEVectorFlags[currentCPECount] = (ULONG)PlatformInt->Flags; // // Save the IO Sapic Vector (that BIOS expects OS to use) for this platform CMC source // HalpCPEIoSapicVector[currentCPECount] = (UCHAR)PlatformInt->IOSAPICVector; // Thierry - WARNING - 09/19/2000 // NT HAL ignores the IO SAPIC vector field for the platform interrupt sources. // NT imposes the CPEI_VECTOR value for Corrected Machine Errors interrupt vector, for all // the destination processors. Actually, the current default is to attach all the processors // IDT[CPEI_VECTOR] with the HAL default ISR - HalpCPEIHandler for the CPE interrupt model. // We will connect the ISR only for the destination processors after testing if judged valid. // The rationales are: // - IOSAPICVector was mostly added in the specs by Intel for IA64 PMI interrupt sources. // These PMI interrupts are not visible by NT. // - NT has no infrastructure at this time to support vector registration for FW/chipset // generated external interrupts visible to NT. // - Having the FW specifying the vector requires the HAL to control the specified // value with its current IDT[] related resources usage and defines actions in case // of conficts. // HalDebugPrint(( HAL_INFO, "HAL: CPE source VECTOR: %x. HAL imposes VECTOR: %x\n", HalpCPEIoSapicVector[currentCPECount], CPEI_VECTOR )); HalpCPEIoSapicVector[currentCPECount] = (UCHAR)(CPEI_VECTOR); // // Save the Destination Processor (that BIOS expects OS to use) for this CPE source) // HalpCPEDestination[currentCPECount] = (USHORT)( (PlatformInt->APICID << 8) | PlatformInt->ACPIEID); // // Force the flags into the SAPIC state // HalpSetCPEVectorState( HalpCPEIntIn[currentCPECount], HalpCPEIoSapicVector[currentCPECount], HalpCPEDestination[currentCPECount], HalpCPEVectorFlags[currentCPECount] ); HalDebugPrint(( HAL_INFO, "HAL: Found an Platform Interrupt VECTOR: %p, %x -> %x, flags: %x\n", PlatformInt, PlatformInt->IOSAPICVector, PlatformInt->GlobalVector, PlatformInt->Flags )); // // Keep track of how many CPE sources are implemented in the platform. // HalpMaxCPEImplemented = ++currentCPECount; } else if ( ( PlatformInt->InterruptType == PLATFORM_INT_PMI ) || ( PlatformInt->InterruptType == PLATFORM_INT_INIT ) ) { HalpWriteRedirEntry( PlatformInt->GlobalVector, PlatformInt->IOSAPICVector, (USHORT)((PlatformInt->APICID <<8) | PlatformInt->ACPIEID), PlatformInt->Flags, PlatformInt->InterruptType ); } return; } BOOLEAN HalpVerifyIoSapic( IN PUCHAR BaseAddress ) /*++ Routine Description: Verify that an IO Sapic Unit exists at the specified address Arguments: BaseAddress - Virtual address of the IO Unit to test. Return Value: BOOLEAN - TRUE if a IO Unit was found at the passed address - FALSE otherwise --*/ { union SapicUnion { ULONG Raw; struct SapicVersion Ver; } Temp1, Temp2; PIO_SAPIC_REGS IoUnitPtr = (PIO_SAPIC_REGS) BaseAddress; // // The documented detection mechanism is to write all zeros to // the Version register. Then read it back. The IO Unit exists if the // same result is read both times and the Version is valid. // IoUnitPtr->RegisterSelect = IO_VERS_REGISTER; IoUnitPtr->RegisterWindow = 0; IoUnitPtr->RegisterSelect = IO_VERS_REGISTER; Temp1.Raw = IoUnitPtr->RegisterWindow; IoUnitPtr->RegisterSelect = IO_VERS_REGISTER; IoUnitPtr->RegisterWindow = 0; IoUnitPtr->RegisterSelect = IO_VERS_REGISTER; Temp2.Raw = IoUnitPtr->RegisterWindow; if ( Temp1.Raw == 0 || (Temp1.Ver.Version != Temp2.Ver.Version) || (Temp1.Ver.MaxRedirEntries != Temp2.Ver.MaxRedirEntries)) { // // No IO Unit There // HalDebugPrint(( HAL_ERROR, "HAL: No IoSapic at %I64x\n", BaseAddress )); return (FALSE); } HalDebugPrint(( HAL_INFO, "HAL: IoSapic found at %I64x, Max Entries = %d\n", BaseAddress, Temp1.Ver.MaxRedirEntries )); return (TRUE); } VOID HalpInitApicDebugMappings( VOID ) /*++ Routine Description: This routine is called at the very beginning of phase 1 initialization. It creates mappings for the APICs using MmMapIoSpace. This will allow us to access their registers from the debugger. A much better solution would be to allow us to describe our memory usage to MM but .... Arguments: Return Value: --*/ { PHYSICAL_ADDRESS physicalAddress; PIO_INTR_CONTROL IoIntrControl; ULONG index; if (HalpMpInfo.IoSapicCount == 0) { // // I doubt this machine is going to get very far without IOAPICs // but there is certainly nothing for this routine to do. return; } ASSERT(HalpApicDebugAddresses == NULL); HalpApicDebugAddresses = ExAllocatePool(NonPagedPool, HalpMpInfo.IoSapicCount * sizeof(*HalpApicDebugAddresses)); if (HalpApicDebugAddresses == NULL) { return; } IoIntrControl = HalpIoSapicList; for (index = 0; index < HalpMpInfo.IoSapicCount; index++) { if (IoIntrControl != NULL) { if (HalpVirtualToPhysical((ULONG_PTR)IoIntrControl, &physicalAddress)) { HalpApicDebugAddresses[index].IoIntrControl = MmMapIoSpace(physicalAddress, sizeof(IO_INTR_CONTROL) + (IoIntrControl->IntiMax - IoIntrControl->IntiBase + 1) * sizeof(IOSAPICINTI), MmCached ); } HalpApicDebugAddresses[index].IoSapicRegs = MmMapIoSpace(IoIntrControl->RegBasePhysical, IO_SAPIC_REGS_SIZE, MmNonCached ); IoIntrControl = IoIntrControl->flink; } else { HalpApicDebugAddresses[index].IoIntrControl = NULL; HalpApicDebugAddresses[index].IoSapicRegs = NULL; } } } VOID HalpSaveInterruptControllerState( VOID ) { HalDebugPrint(( HAL_ERROR, "HAL: HalpSaveInterruptControllerState - not yet implemented\n")); HalpHiberInProgress = TRUE; } VOID HalpRestoreInterruptControllerState( VOID ) { // // Restore the IO APIC state // HalDebugPrint(( HAL_ERROR, "HAL: HalpRestoreInterruptControllerState - not yet implemented\n")); HalpPicStateIntact = TRUE; } VOID HalpSetInterruptControllerWakeupState( ULONG Context ) { HalDebugPrint(( HAL_FATAL_ERROR, "HAL: HalpSetInterruptControllerWakeupState - not yet implemented\n")); KeBugCheckEx(HAL_INITIALIZATION_FAILED, 0, 0, 0 , 0); } BOOLEAN HalpAcpiPicStateIntact( VOID ) { return HalpPicStateIntact; } ULONG HalpAcpiNumProcessors( VOID ) { return HalpMpInfo.ProcessorCount; } VOID HalpMaskAcpiInterrupt( VOID ) { ULONG inti; KAFFINITY affinity; ULONG sciVector = HalpFixedAcpiDescTable.sci_int_vector; if (sciVector < PIC_VECTORS) { sciVector = HalpPicVectorRedirect[sciVector]; } HalpGetSapicInterruptDesc( Internal, 0, sciVector, &inti, &affinity ); HalpDisableRedirEntry(inti); } VOID HalpUnmaskAcpiInterrupt( VOID ) { ULONG inti; KAFFINITY affinity; ULONG sciVector = HalpFixedAcpiDescTable.sci_int_vector; if (sciVector < PIC_VECTORS) { sciVector = HalpPicVectorRedirect[sciVector]; } HalpGetSapicInterruptDesc( Internal, 0, sciVector, &inti, &affinity ); HalpEnableRedirEntry(inti); } NTSTATUS HalpGetApicIdByProcessorNumber( IN UCHAR Processor, IN OUT USHORT *ApicId ) /*++ Routine Description: This function returns an APIC ID for a given processor. Arguments: Processor - The logical processor number that is associated with this APIC ID. ApicId - pointer to a value to fill in with the APIC ID. Return Value: Status. --*/ { ULONG index; for (index = 0; index < HalpMpInfo.ProcessorCount; index++) { if (HalpProcessorInfo[index].NtProcessorNumber == Processor) { // // Return the APIC ID, Extended APIC ID for this // processor. // *ApicId = HalpProcessorInfo[index].LocalApicID; return STATUS_SUCCESS; } } return STATUS_NOT_FOUND; }