1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363 |
- /** @file
- Local APIC Library.
- This local APIC library instance supports x2APIC capable processors
- which have xAPIC and x2APIC modes.
- Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
- Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Register/Intel/Cpuid.h>
- #include <Register/Amd/Cpuid.h>
- #include <Register/Intel/Msr.h>
- #include <Register/Intel/LocalApic.h>
- #include <Library/BaseLib.h>
- #include <Library/DebugLib.h>
- #include <Library/LocalApicLib.h>
- #include <Library/IoLib.h>
- #include <Library/TimerLib.h>
- #include <Library/PcdLib.h>
- #include <Library/UefiCpuLib.h>
- //
- // Library internal functions
- //
- /**
- Determine if the CPU supports the Local APIC Base Address MSR.
- @retval TRUE The CPU supports the Local APIC Base Address MSR.
- @retval FALSE The CPU does not support the Local APIC Base Address MSR.
- **/
- BOOLEAN
- LocalApicBaseAddressMsrSupported (
- VOID
- )
- {
- UINT32 RegEax;
- UINTN FamilyId;
- AsmCpuid (1, &RegEax, NULL, NULL, NULL);
- FamilyId = BitFieldRead32 (RegEax, 8, 11);
- if ((FamilyId == 0x04) || (FamilyId == 0x05)) {
- //
- // CPUs with a FamilyId of 0x04 or 0x05 do not support the
- // Local APIC Base Address MSR
- //
- return FALSE;
- }
- return TRUE;
- }
- /**
- Retrieve the base address of local APIC.
- @return The base address of local APIC.
- **/
- UINTN
- EFIAPI
- GetLocalApicBaseAddress (
- VOID
- )
- {
- MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
- if (!LocalApicBaseAddressMsrSupported ()) {
- //
- // If CPU does not support Local APIC Base Address MSR, then retrieve
- // Local APIC Base Address from PCD
- //
- return PcdGet32 (PcdCpuLocalApicBaseAddress);
- }
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +
- (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
- }
- /**
- Set the base address of local APIC.
- If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
- @param[in] BaseAddress Local APIC base address to be set.
- **/
- VOID
- EFIAPI
- SetLocalApicBaseAddress (
- IN UINTN BaseAddress
- )
- {
- MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
- ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
- if (!LocalApicBaseAddressMsrSupported ()) {
- //
- // Ignore set request of the CPU does not support APIC Base Address MSR
- //
- return;
- }
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- ApicBaseMsr.Bits.ApicBase = (UINT32)(BaseAddress >> 12);
- ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
- }
- /**
- Read from a local APIC register.
- This function reads from a local APIC register either in xAPIC or x2APIC mode.
- It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
- accessed using multiple 32-bit loads or stores, so this function only performs
- 32-bit read.
- @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
- It must be 16-byte aligned.
- @return 32-bit Value read from the register.
- **/
- UINT32
- EFIAPI
- ReadLocalApicReg (
- IN UINTN MmioOffset
- )
- {
- UINT32 MsrIndex;
- ASSERT ((MmioOffset & 0xf) == 0);
- if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
- return MmioRead32 (GetLocalApicBaseAddress () + MmioOffset);
- } else {
- //
- // DFR is not supported in x2APIC mode.
- //
- ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
- //
- // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
- // is not supported in this function for simplicity.
- //
- ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
- MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
- return AsmReadMsr32 (MsrIndex);
- }
- }
- /**
- Write to a local APIC register.
- This function writes to a local APIC register either in xAPIC or x2APIC mode.
- It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
- accessed using multiple 32-bit loads or stores, so this function only performs
- 32-bit write.
- if the register index is invalid or unsupported in current APIC mode, then ASSERT.
- @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
- It must be 16-byte aligned.
- @param Value Value to be written to the register.
- **/
- VOID
- EFIAPI
- WriteLocalApicReg (
- IN UINTN MmioOffset,
- IN UINT32 Value
- )
- {
- UINT32 MsrIndex;
- ASSERT ((MmioOffset & 0xf) == 0);
- if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
- MmioWrite32 (GetLocalApicBaseAddress () + MmioOffset, Value);
- } else {
- //
- // DFR is not supported in x2APIC mode.
- //
- ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
- //
- // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
- // is not supported in this function for simplicity.
- //
- ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
- ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);
- MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
- //
- // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.
- // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
- //
- MemoryFence ();
- AsmWriteMsr32 (MsrIndex, Value);
- }
- }
- /**
- Send an IPI by writing to ICR.
- This function returns after the IPI has been accepted by the target processor.
- @param IcrLow 32-bit value to be written to the low half of ICR.
- @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
- **/
- VOID
- SendIpi (
- IN UINT32 IcrLow,
- IN UINT32 ApicId
- )
- {
- UINT64 MsrValue;
- LOCAL_APIC_ICR_LOW IcrLowReg;
- UINTN LocalApciBaseAddress;
- UINT32 IcrHigh;
- BOOLEAN InterruptState;
- //
- // Legacy APIC or X2APIC?
- //
- if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
- ASSERT (ApicId <= 0xff);
- InterruptState = SaveAndDisableInterrupts ();
- //
- // Get base address of this LAPIC
- //
- LocalApciBaseAddress = GetLocalApicBaseAddress ();
- //
- // Save existing contents of ICR high 32 bits
- //
- IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);
- //
- // Wait for DeliveryStatus clear in case a previous IPI
- // is still being sent
- //
- do {
- IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
- } while (IcrLowReg.Bits.DeliveryStatus != 0);
- //
- // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
- //
- MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
- MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);
- //
- // Wait for DeliveryStatus clear again
- //
- do {
- IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
- } while (IcrLowReg.Bits.DeliveryStatus != 0);
- //
- // And restore old contents of ICR high
- //
- MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);
- SetInterruptState (InterruptState);
- } else {
- //
- // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
- // interrupt in x2APIC mode.
- //
- MsrValue = LShiftU64 ((UINT64)ApicId, 32) | IcrLow;
- AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);
- }
- }
- //
- // Library API implementation functions
- //
- /**
- Get the current local APIC mode.
- If local APIC is disabled, then ASSERT.
- @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
- @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
- **/
- UINTN
- EFIAPI
- GetApicMode (
- VOID
- )
- {
- MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
- if (!LocalApicBaseAddressMsrSupported ()) {
- //
- // If CPU does not support APIC Base Address MSR, then return XAPIC mode
- //
- return LOCAL_APIC_MODE_XAPIC;
- }
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- //
- // Local APIC should have been enabled
- //
- ASSERT (ApicBaseMsr.Bits.EN != 0);
- if (ApicBaseMsr.Bits.EXTD != 0) {
- return LOCAL_APIC_MODE_X2APIC;
- } else {
- return LOCAL_APIC_MODE_XAPIC;
- }
- }
- /**
- Set the current local APIC mode.
- If the specified local APIC mode is not valid, then ASSERT.
- If the specified local APIC mode can't be set as current, then ASSERT.
- @param ApicMode APIC mode to be set.
- @note This API must not be called from an interrupt handler or SMI handler.
- It may result in unpredictable behavior.
- **/
- VOID
- EFIAPI
- SetApicMode (
- IN UINTN ApicMode
- )
- {
- UINTN CurrentMode;
- MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
- if (!LocalApicBaseAddressMsrSupported ()) {
- //
- // Ignore set request if the CPU does not support APIC Base Address MSR
- //
- return;
- }
- CurrentMode = GetApicMode ();
- if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {
- switch (ApicMode) {
- case LOCAL_APIC_MODE_XAPIC:
- break;
- case LOCAL_APIC_MODE_X2APIC:
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- ApicBaseMsr.Bits.EXTD = 1;
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
- break;
- default:
- ASSERT (FALSE);
- }
- } else {
- switch (ApicMode) {
- case LOCAL_APIC_MODE_XAPIC:
- //
- // Transition from x2APIC mode to xAPIC mode is a two-step process:
- // x2APIC -> Local APIC disabled -> xAPIC
- //
- ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
- ApicBaseMsr.Bits.EXTD = 0;
- ApicBaseMsr.Bits.EN = 0;
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
- ApicBaseMsr.Bits.EN = 1;
- AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
- break;
- case LOCAL_APIC_MODE_X2APIC:
- break;
- default:
- ASSERT (FALSE);
- }
- }
- }
- /**
- Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
- In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
- In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
- the 32-bit local APIC ID is returned as initial APIC ID.
- @return 32-bit initial local APIC ID of the executing processor.
- **/
- UINT32
- EFIAPI
- GetInitialApicId (
- VOID
- )
- {
- UINT32 ApicId;
- UINT32 MaxCpuIdIndex;
- UINT32 RegEbx;
- if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
- //
- // Get the max index of basic CPUID
- //
- AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
- //
- // If CPUID Leaf B is supported,
- // And CPUID.0BH:EBX[15:0] reports a non-zero value,
- // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
- // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
- //
- if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
- AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);
- if ((RegEbx & (BIT16 - 1)) != 0) {
- return ApicId;
- }
- }
- AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
- return RegEbx >> 24;
- } else {
- return GetApicId ();
- }
- }
- /**
- Get the local APIC ID of the executing processor.
- @return 32-bit local APIC ID of the executing processor.
- **/
- UINT32
- EFIAPI
- GetApicId (
- VOID
- )
- {
- UINT32 ApicId;
- UINT32 InitApicId;
- ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
- if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
- ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;
- }
- return ApicId;
- }
- /**
- Get the value of the local APIC version register.
- @return the value of the local APIC version register.
- **/
- UINT32
- EFIAPI
- GetApicVersion (
- VOID
- )
- {
- return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
- }
- /**
- Send a Fixed IPI to a specified target processor.
- This function returns after the IPI has been accepted by the target processor.
- @param ApicId The local APIC ID of the target processor.
- @param Vector The vector number of the interrupt being sent.
- **/
- VOID
- EFIAPI
- SendFixedIpi (
- IN UINT32 ApicId,
- IN UINT8 Vector
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.Vector = Vector;
- SendIpi (IcrLow.Uint32, ApicId);
- }
- /**
- Send a Fixed IPI to all processors excluding self.
- This function returns after the IPI has been accepted by the target processors.
- @param Vector The vector number of the interrupt being sent.
- **/
- VOID
- EFIAPI
- SendFixedIpiAllExcludingSelf (
- IN UINT8 Vector
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
- IcrLow.Bits.Vector = Vector;
- SendIpi (IcrLow.Uint32, 0);
- }
- /**
- Send a SMI IPI to a specified target processor.
- This function returns after the IPI has been accepted by the target processor.
- @param ApicId Specify the local APIC ID of the target processor.
- **/
- VOID
- EFIAPI
- SendSmiIpi (
- IN UINT32 ApicId
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
- IcrLow.Bits.Level = 1;
- SendIpi (IcrLow.Uint32, ApicId);
- }
- /**
- Send a SMI IPI to all processors excluding self.
- This function returns after the IPI has been accepted by the target processors.
- **/
- VOID
- EFIAPI
- SendSmiIpiAllExcludingSelf (
- VOID
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
- SendIpi (IcrLow.Uint32, 0);
- }
- /**
- Send an INIT IPI to a specified target processor.
- This function returns after the IPI has been accepted by the target processor.
- @param ApicId Specify the local APIC ID of the target processor.
- **/
- VOID
- EFIAPI
- SendInitIpi (
- IN UINT32 ApicId
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
- IcrLow.Bits.Level = 1;
- SendIpi (IcrLow.Uint32, ApicId);
- }
- /**
- Send an INIT IPI to all processors excluding self.
- This function returns after the IPI has been accepted by the target processors.
- **/
- VOID
- EFIAPI
- SendInitIpiAllExcludingSelf (
- VOID
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- IcrLow.Uint32 = 0;
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
- SendIpi (IcrLow.Uint32, 0);
- }
- /**
- Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
- This function returns after the IPI has been accepted by the target processor.
- if StartupRoutine >= 1M, then ASSERT.
- if StartupRoutine is not multiple of 4K, then ASSERT.
- @param ApicId Specify the local APIC ID of the target processor.
- @param StartupRoutine Points to a start-up routine which is below 1M physical
- address and 4K aligned.
- **/
- VOID
- EFIAPI
- SendInitSipiSipi (
- IN UINT32 ApicId,
- IN UINT32 StartupRoutine
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- ASSERT (StartupRoutine < 0x100000);
- ASSERT ((StartupRoutine & 0xfff) == 0);
- SendInitIpi (ApicId);
- MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));
- IcrLow.Uint32 = 0;
- IcrLow.Bits.Vector = (StartupRoutine >> 12);
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
- IcrLow.Bits.Level = 1;
- SendIpi (IcrLow.Uint32, ApicId);
- if (!StandardSignatureIsAuthenticAMD ()) {
- MicroSecondDelay (200);
- SendIpi (IcrLow.Uint32, ApicId);
- }
- }
- /**
- Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
- This function returns after the IPI has been accepted by the target processors.
- if StartupRoutine >= 1M, then ASSERT.
- if StartupRoutine is not multiple of 4K, then ASSERT.
- @param StartupRoutine Points to a start-up routine which is below 1M physical
- address and 4K aligned.
- **/
- VOID
- EFIAPI
- SendInitSipiSipiAllExcludingSelf (
- IN UINT32 StartupRoutine
- )
- {
- LOCAL_APIC_ICR_LOW IcrLow;
- ASSERT (StartupRoutine < 0x100000);
- ASSERT ((StartupRoutine & 0xfff) == 0);
- SendInitIpiAllExcludingSelf ();
- MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));
- IcrLow.Uint32 = 0;
- IcrLow.Bits.Vector = (StartupRoutine >> 12);
- IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
- IcrLow.Bits.Level = 1;
- IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
- SendIpi (IcrLow.Uint32, 0);
- if (!StandardSignatureIsAuthenticAMD ()) {
- MicroSecondDelay (200);
- SendIpi (IcrLow.Uint32, 0);
- }
- }
- /**
- Initialize the state of the SoftwareEnable bit in the Local APIC
- Spurious Interrupt Vector register.
- @param Enable If TRUE, then set SoftwareEnable to 1
- If FALSE, then set SoftwareEnable to 0.
- **/
- VOID
- EFIAPI
- InitializeLocalApicSoftwareEnable (
- IN BOOLEAN Enable
- )
- {
- LOCAL_APIC_SVR Svr;
- //
- // Set local APIC software-enabled bit.
- //
- Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
- if (Enable) {
- if (Svr.Bits.SoftwareEnable == 0) {
- Svr.Bits.SoftwareEnable = 1;
- WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
- }
- } else {
- if (Svr.Bits.SoftwareEnable == 1) {
- Svr.Bits.SoftwareEnable = 0;
- WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
- }
- }
- }
- /**
- Programming Virtual Wire Mode.
- This function programs the local APIC for virtual wire mode following
- the example described in chapter A.3 of the MP 1.4 spec.
- IOxAPIC is not involved in this type of virtual wire mode.
- **/
- VOID
- EFIAPI
- ProgramVirtualWireMode (
- VOID
- )
- {
- LOCAL_APIC_SVR Svr;
- LOCAL_APIC_LVT_LINT Lint;
- //
- // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
- //
- Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
- Svr.Bits.SpuriousVector = 0xf;
- Svr.Bits.SoftwareEnable = 1;
- WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
- //
- // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
- //
- Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
- Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
- Lint.Bits.InputPinPolarity = 0;
- Lint.Bits.TriggerMode = 0;
- Lint.Bits.Mask = 0;
- WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
- //
- // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
- //
- Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
- Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
- Lint.Bits.InputPinPolarity = 0;
- Lint.Bits.TriggerMode = 0;
- Lint.Bits.Mask = 0;
- WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
- }
- /**
- Disable LINT0 & LINT1 interrupts.
- This function sets the mask flag in the LVT LINT0 & LINT1 registers.
- **/
- VOID
- EFIAPI
- DisableLvtInterrupts (
- VOID
- )
- {
- LOCAL_APIC_LVT_LINT LvtLint;
- LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
- LvtLint.Bits.Mask = 1;
- WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
- LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
- LvtLint.Bits.Mask = 1;
- WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
- }
- /**
- Read the initial count value from the init-count register.
- @return The initial count value read from the init-count register.
- **/
- UINT32
- EFIAPI
- GetApicTimerInitCount (
- VOID
- )
- {
- return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
- }
- /**
- Read the current count value from the current-count register.
- @return The current count value read from the current-count register.
- **/
- UINT32
- EFIAPI
- GetApicTimerCurrentCount (
- VOID
- )
- {
- return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
- }
- /**
- Initialize the local APIC timer.
- The local APIC timer is initialized and enabled.
- @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
- If it is 0, then use the current divide value in the DCR.
- @param InitCount The initial count value.
- @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
- @param Vector The timer interrupt vector number.
- **/
- VOID
- EFIAPI
- InitializeApicTimer (
- IN UINTN DivideValue,
- IN UINT32 InitCount,
- IN BOOLEAN PeriodicMode,
- IN UINT8 Vector
- )
- {
- LOCAL_APIC_DCR Dcr;
- LOCAL_APIC_LVT_TIMER LvtTimer;
- UINT32 Divisor;
- //
- // Ensure local APIC is in software-enabled state.
- //
- InitializeLocalApicSoftwareEnable (TRUE);
- //
- // Program init-count register.
- //
- WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
- if (DivideValue != 0) {
- ASSERT (DivideValue <= 128);
- ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));
- Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
- Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
- Dcr.Bits.DivideValue1 = (Divisor & 0x3);
- Dcr.Bits.DivideValue2 = (Divisor >> 2);
- WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
- }
- //
- // Enable APIC timer interrupt with specified timer mode.
- //
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- if (PeriodicMode) {
- LvtTimer.Bits.TimerMode = 1;
- } else {
- LvtTimer.Bits.TimerMode = 0;
- }
- LvtTimer.Bits.Mask = 0;
- LvtTimer.Bits.Vector = Vector;
- WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
- }
- /**
- Get the state of the local APIC timer.
- This function will ASSERT if the local APIC is not software enabled.
- @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
- @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
- @param Vector Return the timer interrupt vector number.
- **/
- VOID
- EFIAPI
- GetApicTimerState (
- OUT UINTN *DivideValue OPTIONAL,
- OUT BOOLEAN *PeriodicMode OPTIONAL,
- OUT UINT8 *Vector OPTIONAL
- )
- {
- UINT32 Divisor;
- LOCAL_APIC_DCR Dcr;
- LOCAL_APIC_LVT_TIMER LvtTimer;
- //
- // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
- // Vector Register.
- // This bit will be 1, if local APIC is software enabled.
- //
- ASSERT ((ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
- if (DivideValue != NULL) {
- Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
- Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
- Divisor = (Divisor + 1) & 0x7;
- *DivideValue = ((UINTN)1) << Divisor;
- }
- if ((PeriodicMode != NULL) || (Vector != NULL)) {
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- if (PeriodicMode != NULL) {
- if (LvtTimer.Bits.TimerMode == 1) {
- *PeriodicMode = TRUE;
- } else {
- *PeriodicMode = FALSE;
- }
- }
- if (Vector != NULL) {
- *Vector = (UINT8)LvtTimer.Bits.Vector;
- }
- }
- }
- /**
- Enable the local APIC timer interrupt.
- **/
- VOID
- EFIAPI
- EnableApicTimerInterrupt (
- VOID
- )
- {
- LOCAL_APIC_LVT_TIMER LvtTimer;
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- LvtTimer.Bits.Mask = 0;
- WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
- }
- /**
- Disable the local APIC timer interrupt.
- **/
- VOID
- EFIAPI
- DisableApicTimerInterrupt (
- VOID
- )
- {
- LOCAL_APIC_LVT_TIMER LvtTimer;
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- LvtTimer.Bits.Mask = 1;
- WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
- }
- /**
- Get the local APIC timer interrupt state.
- @retval TRUE The local APIC timer interrupt is enabled.
- @retval FALSE The local APIC timer interrupt is disabled.
- **/
- BOOLEAN
- EFIAPI
- GetApicTimerInterruptState (
- VOID
- )
- {
- LOCAL_APIC_LVT_TIMER LvtTimer;
- LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
- return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
- }
- /**
- Send EOI to the local APIC.
- **/
- VOID
- EFIAPI
- SendApicEoi (
- VOID
- )
- {
- WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
- }
- /**
- Get the 32-bit address that a device should use to send a Message Signaled
- Interrupt (MSI) to the Local APIC of the currently executing processor.
- @return 32-bit address used to send an MSI to the Local APIC.
- **/
- UINT32
- EFIAPI
- GetApicMsiAddress (
- VOID
- )
- {
- LOCAL_APIC_MSI_ADDRESS MsiAddress;
- //
- // Return address for an MSI interrupt to be delivered only to the APIC ID
- // of the currently executing processor.
- //
- MsiAddress.Uint32 = 0;
- MsiAddress.Bits.BaseAddress = 0xFEE;
- MsiAddress.Bits.DestinationId = GetApicId ();
- return MsiAddress.Uint32;
- }
- /**
- Get the 64-bit data value that a device should use to send a Message Signaled
- Interrupt (MSI) to the Local APIC of the currently executing processor.
- If Vector is not in range 0x10..0xFE, then ASSERT().
- If DeliveryMode is not supported, then ASSERT().
- @param Vector The 8-bit interrupt vector associated with the MSI.
- Must be in the range 0x10..0xFE
- @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
- is handled. The only supported values are:
- 0: LOCAL_APIC_DELIVERY_MODE_FIXED
- 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
- 2: LOCAL_APIC_DELIVERY_MODE_SMI
- 4: LOCAL_APIC_DELIVERY_MODE_NMI
- 5: LOCAL_APIC_DELIVERY_MODE_INIT
- 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
- @param LevelTriggered TRUE specifies a level triggered interrupt.
- FALSE specifies an edge triggered interrupt.
- @param AssertionLevel Ignored if LevelTriggered is FALSE.
- TRUE specifies a level triggered interrupt that active
- when the interrupt line is asserted.
- FALSE specifies a level triggered interrupt that active
- when the interrupt line is deasserted.
- @return 64-bit data value used to send an MSI to the Local APIC.
- **/
- UINT64
- EFIAPI
- GetApicMsiValue (
- IN UINT8 Vector,
- IN UINTN DeliveryMode,
- IN BOOLEAN LevelTriggered,
- IN BOOLEAN AssertionLevel
- )
- {
- LOCAL_APIC_MSI_DATA MsiData;
- ASSERT (Vector >= 0x10 && Vector <= 0xFE);
- ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
- MsiData.Uint64 = 0;
- MsiData.Bits.Vector = Vector;
- MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
- if (LevelTriggered) {
- MsiData.Bits.TriggerMode = 1;
- if (AssertionLevel) {
- MsiData.Bits.Level = 1;
- }
- }
- return MsiData.Uint64;
- }
- /**
- Get Package ID/Core ID/Thread ID of a processor.
- The algorithm assumes the target system has symmetry across physical
- package boundaries with respect to the number of logical processors
- per package, number of cores per package.
- @param[in] InitialApicId Initial APIC ID of the target logical processor.
- @param[out] Package Returns the processor package ID.
- @param[out] Core Returns the processor core ID.
- @param[out] Thread Returns the processor thread ID.
- **/
- VOID
- EFIAPI
- GetProcessorLocationByApicId (
- IN UINT32 InitialApicId,
- OUT UINT32 *Package OPTIONAL,
- OUT UINT32 *Core OPTIONAL,
- OUT UINT32 *Thread OPTIONAL
- )
- {
- BOOLEAN TopologyLeafSupported;
- CPUID_VERSION_INFO_EBX VersionInfoEbx;
- CPUID_VERSION_INFO_EDX VersionInfoEdx;
- CPUID_CACHE_PARAMS_EAX CacheParamsEax;
- CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
- CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
- CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
- CPUID_AMD_EXTENDED_CPU_SIG_ECX AmdExtendedCpuSigEcx;
- CPUID_AMD_PROCESSOR_TOPOLOGY_EBX AmdProcessorTopologyEbx;
- CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX AmdVirPhyAddressSizeEcx;
- UINT32 MaxStandardCpuIdIndex;
- UINT32 MaxExtendedCpuIdIndex;
- UINT32 SubIndex;
- UINTN LevelType;
- UINT32 MaxLogicProcessorsPerPackage;
- UINT32 MaxCoresPerPackage;
- UINTN ThreadBits;
- UINTN CoreBits;
- //
- // Check if the processor is capable of supporting more than one logical processor.
- //
- AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
- if (VersionInfoEdx.Bits.HTT == 0) {
- if (Thread != NULL) {
- *Thread = 0;
- }
- if (Core != NULL) {
- *Core = 0;
- }
- if (Package != NULL) {
- *Package = 0;
- }
- return;
- }
- //
- // Assume three-level mapping of APIC ID: Package|Core|Thread.
- //
- ThreadBits = 0;
- CoreBits = 0;
- //
- // Get max index of CPUID
- //
- AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
- AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);
- //
- // If the extended topology enumeration leaf is available, it
- // is the preferred mechanism for enumerating topology.
- //
- TopologyLeafSupported = FALSE;
- if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
- AsmCpuidEx (
- CPUID_EXTENDED_TOPOLOGY,
- 0,
- &ExtendedTopologyEax.Uint32,
- &ExtendedTopologyEbx.Uint32,
- &ExtendedTopologyEcx.Uint32,
- NULL
- );
- //
- // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
- // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
- // supported on that processor.
- //
- if (ExtendedTopologyEbx.Uint32 != 0) {
- TopologyLeafSupported = TRUE;
- //
- // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
- // the SMT sub-field of x2APIC ID.
- //
- LevelType = ExtendedTopologyEcx.Bits.LevelType;
- ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
- ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
- //
- // Software must not assume any "level type" encoding
- // value to be related to any sub-leaf index, except sub-leaf 0.
- //
- SubIndex = 1;
- do {
- AsmCpuidEx (
- CPUID_EXTENDED_TOPOLOGY,
- SubIndex,
- &ExtendedTopologyEax.Uint32,
- NULL,
- &ExtendedTopologyEcx.Uint32,
- NULL
- );
- LevelType = ExtendedTopologyEcx.Bits.LevelType;
- if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
- CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
- break;
- }
- SubIndex++;
- } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
- }
- }
- if (!TopologyLeafSupported) {
- //
- // Get logical processor count
- //
- AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
- MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
- //
- // Assume single-core processor
- //
- MaxCoresPerPackage = 1;
- //
- // Check for topology extensions on AMD processor
- //
- if (StandardSignatureIsAuthenticAMD ()) {
- if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {
- AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);
- if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {
- //
- // Account for max possible thread count to decode ApicId
- //
- AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);
- MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;
- //
- // Get cores per processor package
- //
- AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);
- MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);
- }
- }
- } else {
- //
- // Extract core count based on CACHE information
- //
- if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {
- AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
- if (CacheParamsEax.Uint32 != 0) {
- MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
- }
- }
- }
- ThreadBits = (UINTN)(HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
- CoreBits = (UINTN)(HighBitSet32 (MaxCoresPerPackage - 1) + 1);
- }
- if (Thread != NULL) {
- *Thread = InitialApicId & ((1 << ThreadBits) - 1);
- }
- if (Core != NULL) {
- *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
- }
- if (Package != NULL) {
- *Package = (InitialApicId >> (ThreadBits + CoreBits));
- }
- }
- /**
- Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.
- The algorithm assumes the target system has symmetry across physical
- package boundaries with respect to the number of threads per core, number of
- cores per module, number of modules per tile, number of tiles per die, number
- of dies per package.
- @param[in] InitialApicId Initial APIC ID of the target logical processor.
- @param[out] Package Returns the processor package ID.
- @param[out] Die Returns the processor die ID.
- @param[out] Tile Returns the processor tile ID.
- @param[out] Module Returns the processor module ID.
- @param[out] Core Returns the processor core ID.
- @param[out] Thread Returns the processor thread ID.
- **/
- VOID
- EFIAPI
- GetProcessorLocation2ByApicId (
- IN UINT32 InitialApicId,
- OUT UINT32 *Package OPTIONAL,
- OUT UINT32 *Die OPTIONAL,
- OUT UINT32 *Tile OPTIONAL,
- OUT UINT32 *Module OPTIONAL,
- OUT UINT32 *Core OPTIONAL,
- OUT UINT32 *Thread OPTIONAL
- )
- {
- CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
- CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
- UINT32 MaxStandardCpuIdIndex;
- UINT32 Index;
- UINTN LevelType;
- UINT32 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
- UINT32 *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
- for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {
- Bits[LevelType] = 0;
- }
- //
- // Get max index of CPUID
- //
- AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
- if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {
- if (Die != NULL) {
- *Die = 0;
- }
- if (Tile != NULL) {
- *Tile = 0;
- }
- if (Module != NULL) {
- *Module = 0;
- }
- GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);
- return;
- }
- //
- // If the V2 extended topology enumeration leaf is available, it
- // is the preferred mechanism for enumerating topology.
- //
- for (Index = 0; ; Index++) {
- AsmCpuidEx (
- CPUID_V2_EXTENDED_TOPOLOGY,
- Index,
- &ExtendedTopologyEax.Uint32,
- NULL,
- &ExtendedTopologyEcx.Uint32,
- NULL
- );
- LevelType = ExtendedTopologyEcx.Bits.LevelType;
- //
- // first level reported should be SMT.
- //
- ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));
- if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {
- break;
- }
- ASSERT (LevelType < ARRAY_SIZE (Bits));
- Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;
- }
- for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {
- //
- // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored
- // and treated as an extension of the last known level (i.e., level-1 in this case).
- //
- if (Bits[LevelType] == 0) {
- Bits[LevelType] = Bits[LevelType - 1];
- }
- }
- Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;
- Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE] = Die;
- Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE] = Tile;
- Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE] = Module;
- Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE] = Core;
- Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT] = Thread;
- Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;
- for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
- ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1
- ; LevelType++
- )
- {
- if (Location[LevelType] != NULL) {
- //
- // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique
- // topology ID of the next level type.
- //
- *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];
- //
- // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.
- //
- *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;
- }
- }
- }
|