4 This local APIC library instance supports x2APIC capable processors
5 which have xAPIC and x2APIC modes.
7 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
8 Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
10 SPDX-License-Identifier: BSD-2-Clause-Patent
14 #include <Register/Cpuid.h>
15 #include <Register/Amd/Cpuid.h>
16 #include <Register/Msr.h>
17 #include <Register/LocalApic.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/LocalApicLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/TimerLib.h>
24 #include <Library/PcdLib.h>
27 // Library internal functions
31 Determine if the standard CPU signature is "AuthenticAMD".
33 @retval TRUE The CPU signature matches.
34 @retval FALSE The CPU signature does not match.
38 StandardSignatureIsAuthenticAMD (
46 AsmCpuid (CPUID_SIGNATURE
, NULL
, &RegEbx
, &RegEcx
, &RegEdx
);
47 return (RegEbx
== CPUID_SIGNATURE_AUTHENTIC_AMD_EBX
&&
48 RegEcx
== CPUID_SIGNATURE_AUTHENTIC_AMD_ECX
&&
49 RegEdx
== CPUID_SIGNATURE_AUTHENTIC_AMD_EDX
);
53 Determine if the CPU supports the Local APIC Base Address MSR.
55 @retval TRUE The CPU supports the Local APIC Base Address MSR.
56 @retval FALSE The CPU does not support the Local APIC Base Address MSR.
60 LocalApicBaseAddressMsrSupported (
67 AsmCpuid (1, &RegEax
, NULL
, NULL
, NULL
);
68 FamilyId
= BitFieldRead32 (RegEax
, 8, 11);
69 if (FamilyId
== 0x04 || FamilyId
== 0x05) {
71 // CPUs with a FamilyId of 0x04 or 0x05 do not support the
72 // Local APIC Base Address MSR
80 Retrieve the base address of local APIC.
82 @return The base address of local APIC.
87 GetLocalApicBaseAddress (
91 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
93 if (!LocalApicBaseAddressMsrSupported ()) {
95 // If CPU does not support Local APIC Base Address MSR, then retrieve
96 // Local APIC Base Address from PCD
98 return PcdGet32 (PcdCpuLocalApicBaseAddress
);
101 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
103 return (UINTN
)(LShiftU64 ((UINT64
) ApicBaseMsr
.Bits
.ApicBaseHi
, 32)) +
104 (((UINTN
)ApicBaseMsr
.Bits
.ApicBase
) << 12);
108 Set the base address of local APIC.
110 If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
112 @param[in] BaseAddress Local APIC base address to be set.
117 SetLocalApicBaseAddress (
121 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
123 ASSERT ((BaseAddress
& (SIZE_4KB
- 1)) == 0);
125 if (!LocalApicBaseAddressMsrSupported ()) {
127 // Ignore set request of the CPU does not support APIC Base Address MSR
132 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
134 ApicBaseMsr
.Bits
.ApicBase
= (UINT32
) (BaseAddress
>> 12);
135 ApicBaseMsr
.Bits
.ApicBaseHi
= (UINT32
) (RShiftU64((UINT64
) BaseAddress
, 32));
137 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
141 Read from a local APIC register.
143 This function reads from a local APIC register either in xAPIC or x2APIC mode.
144 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
145 accessed using multiple 32-bit loads or stores, so this function only performs
148 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
149 It must be 16-byte aligned.
151 @return 32-bit Value read from the register.
161 ASSERT ((MmioOffset
& 0xf) == 0);
163 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
164 return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset
);
167 // DFR is not supported in x2APIC mode.
169 ASSERT (MmioOffset
!= XAPIC_ICR_DFR_OFFSET
);
171 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
172 // is not supported in this function for simplicity.
174 ASSERT (MmioOffset
!= XAPIC_ICR_HIGH_OFFSET
);
176 MsrIndex
= (UINT32
)(MmioOffset
>> 4) + X2APIC_MSR_BASE_ADDRESS
;
177 return AsmReadMsr32 (MsrIndex
);
182 Write to a local APIC register.
184 This function writes to a local APIC register either in xAPIC or x2APIC mode.
185 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
186 accessed using multiple 32-bit loads or stores, so this function only performs
189 if the register index is invalid or unsupported in current APIC mode, then ASSERT.
191 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
192 It must be 16-byte aligned.
193 @param Value Value to be written to the register.
204 ASSERT ((MmioOffset
& 0xf) == 0);
206 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
207 MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset
, Value
);
210 // DFR is not supported in x2APIC mode.
212 ASSERT (MmioOffset
!= XAPIC_ICR_DFR_OFFSET
);
214 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
215 // is not supported in this function for simplicity.
217 ASSERT (MmioOffset
!= XAPIC_ICR_HIGH_OFFSET
);
218 ASSERT (MmioOffset
!= XAPIC_ICR_LOW_OFFSET
);
220 MsrIndex
= (UINT32
)(MmioOffset
>> 4) + X2APIC_MSR_BASE_ADDRESS
;
222 // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.
223 // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
226 AsmWriteMsr32 (MsrIndex
, Value
);
231 Send an IPI by writing to ICR.
233 This function returns after the IPI has been accepted by the target processor.
235 @param IcrLow 32-bit value to be written to the low half of ICR.
236 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
245 LOCAL_APIC_ICR_LOW IcrLowReg
;
246 UINTN LocalApciBaseAddress
;
248 BOOLEAN InterruptState
;
251 // Legacy APIC or X2APIC?
253 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
254 ASSERT (ApicId
<= 0xff);
256 InterruptState
= SaveAndDisableInterrupts ();
259 // Get base address of this LAPIC
261 LocalApciBaseAddress
= GetLocalApicBaseAddress();
264 // Save existing contents of ICR high 32 bits
266 IcrHigh
= MmioRead32 (LocalApciBaseAddress
+ XAPIC_ICR_HIGH_OFFSET
);
269 // Wait for DeliveryStatus clear in case a previous IPI
270 // is still being sent
273 IcrLowReg
.Uint32
= MmioRead32 (LocalApciBaseAddress
+ XAPIC_ICR_LOW_OFFSET
);
274 } while (IcrLowReg
.Bits
.DeliveryStatus
!= 0);
277 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
279 MmioWrite32 (LocalApciBaseAddress
+ XAPIC_ICR_HIGH_OFFSET
, ApicId
<< 24);
280 MmioWrite32 (LocalApciBaseAddress
+ XAPIC_ICR_LOW_OFFSET
, IcrLow
);
283 // Wait for DeliveryStatus clear again
286 IcrLowReg
.Uint32
= MmioRead32 (LocalApciBaseAddress
+ XAPIC_ICR_LOW_OFFSET
);
287 } while (IcrLowReg
.Bits
.DeliveryStatus
!= 0);
290 // And restore old contents of ICR high
292 MmioWrite32 (LocalApciBaseAddress
+ XAPIC_ICR_HIGH_OFFSET
, IcrHigh
);
294 SetInterruptState (InterruptState
);
298 // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
299 // interrupt in x2APIC mode.
301 MsrValue
= LShiftU64 ((UINT64
) ApicId
, 32) | IcrLow
;
302 AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS
, MsrValue
);
307 // Library API implementation functions
311 Get the current local APIC mode.
313 If local APIC is disabled, then ASSERT.
315 @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
316 @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
324 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
326 if (!LocalApicBaseAddressMsrSupported ()) {
328 // If CPU does not support APIC Base Address MSR, then return XAPIC mode
330 return LOCAL_APIC_MODE_XAPIC
;
333 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
335 // Local APIC should have been enabled
337 ASSERT (ApicBaseMsr
.Bits
.EN
!= 0);
338 if (ApicBaseMsr
.Bits
.EXTD
!= 0) {
339 return LOCAL_APIC_MODE_X2APIC
;
341 return LOCAL_APIC_MODE_XAPIC
;
346 Set the current local APIC mode.
348 If the specified local APIC mode is not valid, then ASSERT.
349 If the specified local APIC mode can't be set as current, then ASSERT.
351 @param ApicMode APIC mode to be set.
353 @note This API must not be called from an interrupt handler or SMI handler.
354 It may result in unpredictable behavior.
363 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr
;
365 if (!LocalApicBaseAddressMsrSupported ()) {
367 // Ignore set request if the CPU does not support APIC Base Address MSR
372 CurrentMode
= GetApicMode ();
373 if (CurrentMode
== LOCAL_APIC_MODE_XAPIC
) {
375 case LOCAL_APIC_MODE_XAPIC
:
377 case LOCAL_APIC_MODE_X2APIC
:
378 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
379 ApicBaseMsr
.Bits
.EXTD
= 1;
380 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
387 case LOCAL_APIC_MODE_XAPIC
:
389 // Transition from x2APIC mode to xAPIC mode is a two-step process:
390 // x2APIC -> Local APIC disabled -> xAPIC
392 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE
);
393 ApicBaseMsr
.Bits
.EXTD
= 0;
394 ApicBaseMsr
.Bits
.EN
= 0;
395 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
396 ApicBaseMsr
.Bits
.EN
= 1;
397 AsmWriteMsr64 (MSR_IA32_APIC_BASE
, ApicBaseMsr
.Uint64
);
399 case LOCAL_APIC_MODE_X2APIC
:
408 Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
410 In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
411 In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
412 the 32-bit local APIC ID is returned as initial APIC ID.
414 @return 32-bit initial local APIC ID of the executing processor.
423 UINT32 MaxCpuIdIndex
;
426 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
428 // Get the max index of basic CPUID
430 AsmCpuid (CPUID_SIGNATURE
, &MaxCpuIdIndex
, NULL
, NULL
, NULL
);
432 // If CPUID Leaf B is supported,
433 // And CPUID.0BH:EBX[15:0] reports a non-zero value,
434 // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
435 // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
437 if (MaxCpuIdIndex
>= CPUID_EXTENDED_TOPOLOGY
) {
438 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY
, 0, NULL
, &RegEbx
, NULL
, &ApicId
);
439 if ((RegEbx
& (BIT16
- 1)) != 0) {
443 AsmCpuid (CPUID_VERSION_INFO
, NULL
, &RegEbx
, NULL
, NULL
);
451 Get the local APIC ID of the executing processor.
453 @return 32-bit local APIC ID of the executing processor.
464 ApicId
= ReadLocalApicReg (XAPIC_ID_OFFSET
);
465 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
466 ApicId
= ((InitApicId
= GetInitialApicId ()) < 0x100) ? (ApicId
>> 24) : InitApicId
;
473 Get the value of the local APIC version register.
475 @return the value of the local APIC version register.
483 return ReadLocalApicReg (XAPIC_VERSION_OFFSET
);
487 Send a Fixed IPI to a specified target processor.
489 This function returns after the IPI has been accepted by the target processor.
491 @param ApicId The local APIC ID of the target processor.
492 @param Vector The vector number of the interrupt being sent.
501 LOCAL_APIC_ICR_LOW IcrLow
;
504 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_FIXED
;
505 IcrLow
.Bits
.Level
= 1;
506 IcrLow
.Bits
.Vector
= Vector
;
507 SendIpi (IcrLow
.Uint32
, ApicId
);
511 Send a Fixed IPI to all processors excluding self.
513 This function returns after the IPI has been accepted by the target processors.
515 @param Vector The vector number of the interrupt being sent.
519 SendFixedIpiAllExcludingSelf (
523 LOCAL_APIC_ICR_LOW IcrLow
;
526 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_FIXED
;
527 IcrLow
.Bits
.Level
= 1;
528 IcrLow
.Bits
.DestinationShorthand
= LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF
;
529 IcrLow
.Bits
.Vector
= Vector
;
530 SendIpi (IcrLow
.Uint32
, 0);
534 Send a SMI IPI to a specified target processor.
536 This function returns after the IPI has been accepted by the target processor.
538 @param ApicId Specify the local APIC ID of the target processor.
546 LOCAL_APIC_ICR_LOW IcrLow
;
549 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_SMI
;
550 IcrLow
.Bits
.Level
= 1;
551 SendIpi (IcrLow
.Uint32
, ApicId
);
555 Send a SMI IPI to all processors excluding self.
557 This function returns after the IPI has been accepted by the target processors.
561 SendSmiIpiAllExcludingSelf (
565 LOCAL_APIC_ICR_LOW IcrLow
;
568 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_SMI
;
569 IcrLow
.Bits
.Level
= 1;
570 IcrLow
.Bits
.DestinationShorthand
= LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF
;
571 SendIpi (IcrLow
.Uint32
, 0);
575 Send an INIT IPI to a specified target processor.
577 This function returns after the IPI has been accepted by the target processor.
579 @param ApicId Specify the local APIC ID of the target processor.
587 LOCAL_APIC_ICR_LOW IcrLow
;
590 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_INIT
;
591 IcrLow
.Bits
.Level
= 1;
592 SendIpi (IcrLow
.Uint32
, ApicId
);
596 Send an INIT IPI to all processors excluding self.
598 This function returns after the IPI has been accepted by the target processors.
602 SendInitIpiAllExcludingSelf (
606 LOCAL_APIC_ICR_LOW IcrLow
;
609 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_INIT
;
610 IcrLow
.Bits
.Level
= 1;
611 IcrLow
.Bits
.DestinationShorthand
= LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF
;
612 SendIpi (IcrLow
.Uint32
, 0);
616 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
618 This function returns after the IPI has been accepted by the target processor.
620 if StartupRoutine >= 1M, then ASSERT.
621 if StartupRoutine is not multiple of 4K, then ASSERT.
623 @param ApicId Specify the local APIC ID of the target processor.
624 @param StartupRoutine Points to a start-up routine which is below 1M physical
625 address and 4K aligned.
631 IN UINT32 StartupRoutine
634 LOCAL_APIC_ICR_LOW IcrLow
;
636 ASSERT (StartupRoutine
< 0x100000);
637 ASSERT ((StartupRoutine
& 0xfff) == 0);
639 SendInitIpi (ApicId
);
640 MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds
));
642 IcrLow
.Bits
.Vector
= (StartupRoutine
>> 12);
643 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_STARTUP
;
644 IcrLow
.Bits
.Level
= 1;
645 SendIpi (IcrLow
.Uint32
, ApicId
);
646 if (!StandardSignatureIsAuthenticAMD ()) {
647 MicroSecondDelay (200);
648 SendIpi (IcrLow
.Uint32
, ApicId
);
653 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
655 This function returns after the IPI has been accepted by the target processors.
657 if StartupRoutine >= 1M, then ASSERT.
658 if StartupRoutine is not multiple of 4K, then ASSERT.
660 @param StartupRoutine Points to a start-up routine which is below 1M physical
661 address and 4K aligned.
665 SendInitSipiSipiAllExcludingSelf (
666 IN UINT32 StartupRoutine
669 LOCAL_APIC_ICR_LOW IcrLow
;
671 ASSERT (StartupRoutine
< 0x100000);
672 ASSERT ((StartupRoutine
& 0xfff) == 0);
674 SendInitIpiAllExcludingSelf ();
675 MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds
));
677 IcrLow
.Bits
.Vector
= (StartupRoutine
>> 12);
678 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_STARTUP
;
679 IcrLow
.Bits
.Level
= 1;
680 IcrLow
.Bits
.DestinationShorthand
= LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF
;
681 SendIpi (IcrLow
.Uint32
, 0);
682 if (!StandardSignatureIsAuthenticAMD ()) {
683 MicroSecondDelay (200);
684 SendIpi (IcrLow
.Uint32
, 0);
689 Initialize the state of the SoftwareEnable bit in the Local APIC
690 Spurious Interrupt Vector register.
692 @param Enable If TRUE, then set SoftwareEnable to 1
693 If FALSE, then set SoftwareEnable to 0.
698 InitializeLocalApicSoftwareEnable (
705 // Set local APIC software-enabled bit.
707 Svr
.Uint32
= ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
);
709 if (Svr
.Bits
.SoftwareEnable
== 0) {
710 Svr
.Bits
.SoftwareEnable
= 1;
711 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
, Svr
.Uint32
);
714 if (Svr
.Bits
.SoftwareEnable
== 1) {
715 Svr
.Bits
.SoftwareEnable
= 0;
716 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
, Svr
.Uint32
);
722 Programming Virtual Wire Mode.
724 This function programs the local APIC for virtual wire mode following
725 the example described in chapter A.3 of the MP 1.4 spec.
727 IOxAPIC is not involved in this type of virtual wire mode.
731 ProgramVirtualWireMode (
736 LOCAL_APIC_LVT_LINT Lint
;
739 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
741 Svr
.Uint32
= ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
);
742 Svr
.Bits
.SpuriousVector
= 0xf;
743 Svr
.Bits
.SoftwareEnable
= 1;
744 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
, Svr
.Uint32
);
747 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
749 Lint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET
);
750 Lint
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_EXTINT
;
751 Lint
.Bits
.InputPinPolarity
= 0;
752 Lint
.Bits
.TriggerMode
= 0;
754 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET
, Lint
.Uint32
);
757 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
759 Lint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET
);
760 Lint
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_NMI
;
761 Lint
.Bits
.InputPinPolarity
= 0;
762 Lint
.Bits
.TriggerMode
= 0;
764 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET
, Lint
.Uint32
);
768 Disable LINT0 & LINT1 interrupts.
770 This function sets the mask flag in the LVT LINT0 & LINT1 registers.
774 DisableLvtInterrupts (
778 LOCAL_APIC_LVT_LINT LvtLint
;
780 LvtLint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET
);
781 LvtLint
.Bits
.Mask
= 1;
782 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET
, LvtLint
.Uint32
);
784 LvtLint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET
);
785 LvtLint
.Bits
.Mask
= 1;
786 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET
, LvtLint
.Uint32
);
790 Read the initial count value from the init-count register.
792 @return The initial count value read from the init-count register.
796 GetApicTimerInitCount (
800 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET
);
804 Read the current count value from the current-count register.
806 @return The current count value read from the current-count register.
810 GetApicTimerCurrentCount (
814 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET
);
818 Initialize the local APIC timer.
820 The local APIC timer is initialized and enabled.
822 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
823 If it is 0, then use the current divide value in the DCR.
824 @param InitCount The initial count value.
825 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
826 @param Vector The timer interrupt vector number.
830 InitializeApicTimer (
831 IN UINTN DivideValue
,
833 IN BOOLEAN PeriodicMode
,
838 LOCAL_APIC_LVT_TIMER LvtTimer
;
842 // Ensure local APIC is in software-enabled state.
844 InitializeLocalApicSoftwareEnable (TRUE
);
847 // Program init-count register.
849 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET
, InitCount
);
851 if (DivideValue
!= 0) {
852 ASSERT (DivideValue
<= 128);
853 ASSERT (DivideValue
== GetPowerOfTwo32((UINT32
)DivideValue
));
854 Divisor
= (UINT32
)((HighBitSet32 ((UINT32
)DivideValue
) - 1) & 0x7);
856 Dcr
.Uint32
= ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
);
857 Dcr
.Bits
.DivideValue1
= (Divisor
& 0x3);
858 Dcr
.Bits
.DivideValue2
= (Divisor
>> 2);
859 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
, Dcr
.Uint32
);
863 // Enable APIC timer interrupt with specified timer mode.
865 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
867 LvtTimer
.Bits
.TimerMode
= 1;
869 LvtTimer
.Bits
.TimerMode
= 0;
871 LvtTimer
.Bits
.Mask
= 0;
872 LvtTimer
.Bits
.Vector
= Vector
;
873 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
877 Get the state of the local APIC timer.
879 This function will ASSERT if the local APIC is not software enabled.
881 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
882 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
883 @param Vector Return the timer interrupt vector number.
888 OUT UINTN
*DivideValue OPTIONAL
,
889 OUT BOOLEAN
*PeriodicMode OPTIONAL
,
890 OUT UINT8
*Vector OPTIONAL
895 LOCAL_APIC_LVT_TIMER LvtTimer
;
898 // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
900 // This bit will be 1, if local APIC is software enabled.
902 ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET
) & BIT8
) != 0);
904 if (DivideValue
!= NULL
) {
905 Dcr
.Uint32
= ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
);
906 Divisor
= Dcr
.Bits
.DivideValue1
| (Dcr
.Bits
.DivideValue2
<< 2);
907 Divisor
= (Divisor
+ 1) & 0x7;
908 *DivideValue
= ((UINTN
)1) << Divisor
;
911 if (PeriodicMode
!= NULL
|| Vector
!= NULL
) {
912 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
913 if (PeriodicMode
!= NULL
) {
914 if (LvtTimer
.Bits
.TimerMode
== 1) {
915 *PeriodicMode
= TRUE
;
917 *PeriodicMode
= FALSE
;
920 if (Vector
!= NULL
) {
921 *Vector
= (UINT8
) LvtTimer
.Bits
.Vector
;
927 Enable the local APIC timer interrupt.
931 EnableApicTimerInterrupt (
935 LOCAL_APIC_LVT_TIMER LvtTimer
;
937 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
938 LvtTimer
.Bits
.Mask
= 0;
939 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
943 Disable the local APIC timer interrupt.
947 DisableApicTimerInterrupt (
951 LOCAL_APIC_LVT_TIMER LvtTimer
;
953 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
954 LvtTimer
.Bits
.Mask
= 1;
955 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
959 Get the local APIC timer interrupt state.
961 @retval TRUE The local APIC timer interrupt is enabled.
962 @retval FALSE The local APIC timer interrupt is disabled.
966 GetApicTimerInterruptState (
970 LOCAL_APIC_LVT_TIMER LvtTimer
;
972 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
973 return (BOOLEAN
)(LvtTimer
.Bits
.Mask
== 0);
977 Send EOI to the local APIC.
985 WriteLocalApicReg (XAPIC_EOI_OFFSET
, 0);
989 Get the 32-bit address that a device should use to send a Message Signaled
990 Interrupt (MSI) to the Local APIC of the currently executing processor.
992 @return 32-bit address used to send an MSI to the Local APIC.
1000 LOCAL_APIC_MSI_ADDRESS MsiAddress
;
1003 // Return address for an MSI interrupt to be delivered only to the APIC ID
1004 // of the currently executing processor.
1006 MsiAddress
.Uint32
= 0;
1007 MsiAddress
.Bits
.BaseAddress
= 0xFEE;
1008 MsiAddress
.Bits
.DestinationId
= GetApicId ();
1009 return MsiAddress
.Uint32
;
1013 Get the 64-bit data value that a device should use to send a Message Signaled
1014 Interrupt (MSI) to the Local APIC of the currently executing processor.
1016 If Vector is not in range 0x10..0xFE, then ASSERT().
1017 If DeliveryMode is not supported, then ASSERT().
1019 @param Vector The 8-bit interrupt vector associated with the MSI.
1020 Must be in the range 0x10..0xFE
1021 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
1022 is handled. The only supported values are:
1023 0: LOCAL_APIC_DELIVERY_MODE_FIXED
1024 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
1025 2: LOCAL_APIC_DELIVERY_MODE_SMI
1026 4: LOCAL_APIC_DELIVERY_MODE_NMI
1027 5: LOCAL_APIC_DELIVERY_MODE_INIT
1028 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
1030 @param LevelTriggered TRUE specifies a level triggered interrupt.
1031 FALSE specifies an edge triggered interrupt.
1032 @param AssertionLevel Ignored if LevelTriggered is FALSE.
1033 TRUE specifies a level triggered interrupt that active
1034 when the interrupt line is asserted.
1035 FALSE specifies a level triggered interrupt that active
1036 when the interrupt line is deasserted.
1038 @return 64-bit data value used to send an MSI to the Local APIC.
1044 IN UINTN DeliveryMode
,
1045 IN BOOLEAN LevelTriggered
,
1046 IN BOOLEAN AssertionLevel
1049 LOCAL_APIC_MSI_DATA MsiData
;
1051 ASSERT (Vector
>= 0x10 && Vector
<= 0xFE);
1052 ASSERT (DeliveryMode
< 8 && DeliveryMode
!= 6 && DeliveryMode
!= 3);
1055 MsiData
.Bits
.Vector
= Vector
;
1056 MsiData
.Bits
.DeliveryMode
= (UINT32
)DeliveryMode
;
1057 if (LevelTriggered
) {
1058 MsiData
.Bits
.TriggerMode
= 1;
1059 if (AssertionLevel
) {
1060 MsiData
.Bits
.Level
= 1;
1063 return MsiData
.Uint64
;
1067 Get Package ID/Core ID/Thread ID of a processor.
1069 The algorithm assumes the target system has symmetry across physical
1070 package boundaries with respect to the number of logical processors
1071 per package, number of cores per package.
1073 @param[in] InitialApicId Initial APIC ID of the target logical processor.
1074 @param[out] Package Returns the processor package ID.
1075 @param[out] Core Returns the processor core ID.
1076 @param[out] Thread Returns the processor thread ID.
1080 GetProcessorLocationByApicId (
1081 IN UINT32 InitialApicId
,
1082 OUT UINT32
*Package OPTIONAL
,
1083 OUT UINT32
*Core OPTIONAL
,
1084 OUT UINT32
*Thread OPTIONAL
1087 BOOLEAN TopologyLeafSupported
;
1088 CPUID_VERSION_INFO_EBX VersionInfoEbx
;
1089 CPUID_VERSION_INFO_EDX VersionInfoEdx
;
1090 CPUID_CACHE_PARAMS_EAX CacheParamsEax
;
1091 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax
;
1092 CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx
;
1093 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx
;
1094 CPUID_AMD_EXTENDED_CPU_SIG_ECX AmdExtendedCpuSigEcx
;
1095 CPUID_AMD_PROCESSOR_TOPOLOGY_EBX AmdProcessorTopologyEbx
;
1096 CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX AmdVirPhyAddressSizeEcx
;
1097 UINT32 MaxStandardCpuIdIndex
;
1098 UINT32 MaxExtendedCpuIdIndex
;
1101 UINT32 MaxLogicProcessorsPerPackage
;
1102 UINT32 MaxCoresPerPackage
;
1107 // Check if the processor is capable of supporting more than one logical processor.
1109 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, NULL
, &VersionInfoEdx
.Uint32
);
1110 if (VersionInfoEdx
.Bits
.HTT
== 0) {
1111 if (Thread
!= NULL
) {
1117 if (Package
!= NULL
) {
1124 // Assume three-level mapping of APIC ID: Package|Core|Thread.
1130 // Get max index of CPUID
1132 AsmCpuid (CPUID_SIGNATURE
, &MaxStandardCpuIdIndex
, NULL
, NULL
, NULL
);
1133 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &MaxExtendedCpuIdIndex
, NULL
, NULL
, NULL
);
1136 // If the extended topology enumeration leaf is available, it
1137 // is the preferred mechanism for enumerating topology.
1139 TopologyLeafSupported
= FALSE
;
1140 if (MaxStandardCpuIdIndex
>= CPUID_EXTENDED_TOPOLOGY
) {
1142 CPUID_EXTENDED_TOPOLOGY
,
1144 &ExtendedTopologyEax
.Uint32
,
1145 &ExtendedTopologyEbx
.Uint32
,
1146 &ExtendedTopologyEcx
.Uint32
,
1150 // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
1151 // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
1152 // supported on that processor.
1154 if (ExtendedTopologyEbx
.Uint32
!= 0) {
1155 TopologyLeafSupported
= TRUE
;
1158 // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
1159 // the SMT sub-field of x2APIC ID.
1161 LevelType
= ExtendedTopologyEcx
.Bits
.LevelType
;
1162 ASSERT (LevelType
== CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
);
1163 ThreadBits
= ExtendedTopologyEax
.Bits
.ApicIdShift
;
1166 // Software must not assume any "level type" encoding
1167 // value to be related to any sub-leaf index, except sub-leaf 0.
1172 CPUID_EXTENDED_TOPOLOGY
,
1174 &ExtendedTopologyEax
.Uint32
,
1176 &ExtendedTopologyEcx
.Uint32
,
1179 LevelType
= ExtendedTopologyEcx
.Bits
.LevelType
;
1180 if (LevelType
== CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE
) {
1181 CoreBits
= ExtendedTopologyEax
.Bits
.ApicIdShift
- ThreadBits
;
1185 } while (LevelType
!= CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID
);
1189 if (!TopologyLeafSupported
) {
1191 // Get logical processor count
1193 AsmCpuid (CPUID_VERSION_INFO
, NULL
, &VersionInfoEbx
.Uint32
, NULL
, NULL
);
1194 MaxLogicProcessorsPerPackage
= VersionInfoEbx
.Bits
.MaximumAddressableIdsForLogicalProcessors
;
1197 // Assume single-core processor
1199 MaxCoresPerPackage
= 1;
1202 // Check for topology extensions on AMD processor
1204 if (StandardSignatureIsAuthenticAMD()) {
1205 if (MaxExtendedCpuIdIndex
>= CPUID_AMD_PROCESSOR_TOPOLOGY
) {
1206 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, &AmdExtendedCpuSigEcx
.Uint32
, NULL
);
1207 if (AmdExtendedCpuSigEcx
.Bits
.TopologyExtensions
!= 0) {
1209 // Account for max possible thread count to decode ApicId
1211 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE
, NULL
, NULL
, &AmdVirPhyAddressSizeEcx
.Uint32
, NULL
);
1212 MaxLogicProcessorsPerPackage
= 1 << AmdVirPhyAddressSizeEcx
.Bits
.ApicIdCoreIdSize
;
1215 // Get cores per processor package
1217 AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY
, NULL
, &AmdProcessorTopologyEbx
.Uint32
, NULL
, NULL
);
1218 MaxCoresPerPackage
= MaxLogicProcessorsPerPackage
/ (AmdProcessorTopologyEbx
.Bits
.ThreadsPerCore
+ 1);
1224 // Extract core count based on CACHE information
1226 if (MaxStandardCpuIdIndex
>= CPUID_CACHE_PARAMS
) {
1227 AsmCpuidEx (CPUID_CACHE_PARAMS
, 0, &CacheParamsEax
.Uint32
, NULL
, NULL
, NULL
);
1228 if (CacheParamsEax
.Uint32
!= 0) {
1229 MaxCoresPerPackage
= CacheParamsEax
.Bits
.MaximumAddressableIdsForLogicalProcessors
+ 1;
1234 ThreadBits
= (UINTN
)(HighBitSet32(MaxLogicProcessorsPerPackage
/ MaxCoresPerPackage
- 1) + 1);
1235 CoreBits
= (UINTN
)(HighBitSet32(MaxCoresPerPackage
- 1) + 1);
1238 if (Thread
!= NULL
) {
1239 *Thread
= InitialApicId
& ((1 << ThreadBits
) - 1);
1242 *Core
= (InitialApicId
>> ThreadBits
) & ((1 << CoreBits
) - 1);
1244 if (Package
!= NULL
) {
1245 *Package
= (InitialApicId
>> (ThreadBits
+ CoreBits
));
1250 Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.
1252 The algorithm assumes the target system has symmetry across physical
1253 package boundaries with respect to the number of threads per core, number of
1254 cores per module, number of modules per tile, number of tiles per die, number
1255 of dies per package.
1257 @param[in] InitialApicId Initial APIC ID of the target logical processor.
1258 @param[out] Package Returns the processor package ID.
1259 @param[out] Die Returns the processor die ID.
1260 @param[out] Tile Returns the processor tile ID.
1261 @param[out] Module Returns the processor module ID.
1262 @param[out] Core Returns the processor core ID.
1263 @param[out] Thread Returns the processor thread ID.
1267 GetProcessorLocation2ByApicId (
1268 IN UINT32 InitialApicId
,
1269 OUT UINT32
*Package OPTIONAL
,
1270 OUT UINT32
*Die OPTIONAL
,
1271 OUT UINT32
*Tile OPTIONAL
,
1272 OUT UINT32
*Module OPTIONAL
,
1273 OUT UINT32
*Core OPTIONAL
,
1274 OUT UINT32
*Thread OPTIONAL
1277 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax
;
1278 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx
;
1279 UINT32 MaxStandardCpuIdIndex
;
1282 UINT32 Bits
[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE
+ 2];
1283 UINT32
*Location
[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE
+ 2];
1285 for (LevelType
= 0; LevelType
< ARRAY_SIZE (Bits
); LevelType
++) {
1286 Bits
[LevelType
] = 0;
1290 // Get max index of CPUID
1292 AsmCpuid (CPUID_SIGNATURE
, &MaxStandardCpuIdIndex
, NULL
, NULL
, NULL
);
1293 if (MaxStandardCpuIdIndex
< CPUID_V2_EXTENDED_TOPOLOGY
) {
1300 if (Module
!= NULL
) {
1303 GetProcessorLocationByApicId (InitialApicId
, Package
, Core
, Thread
);
1308 // If the V2 extended topology enumeration leaf is available, it
1309 // is the preferred mechanism for enumerating topology.
1311 for (Index
= 0; ; Index
++) {
1313 CPUID_V2_EXTENDED_TOPOLOGY
,
1315 &ExtendedTopologyEax
.Uint32
,
1317 &ExtendedTopologyEcx
.Uint32
,
1321 LevelType
= ExtendedTopologyEcx
.Bits
.LevelType
;
1324 // first level reported should be SMT.
1326 ASSERT ((Index
!= 0) || (LevelType
== CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
));
1327 if (LevelType
== CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID
) {
1330 ASSERT (LevelType
< ARRAY_SIZE (Bits
));
1331 Bits
[LevelType
] = ExtendedTopologyEax
.Bits
.ApicIdShift
;
1334 for (LevelType
= CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE
; LevelType
< ARRAY_SIZE (Bits
); LevelType
++) {
1336 // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored
1337 // and treated as an extension of the last known level (i.e., level-1 in this case).
1339 if (Bits
[LevelType
] == 0) {
1340 Bits
[LevelType
] = Bits
[LevelType
- 1];
1344 Location
[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE
+ 1] = Package
;
1345 Location
[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE
] = Die
;
1346 Location
[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE
] = Tile
;
1347 Location
[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE
] = Module
;
1348 Location
[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE
] = Core
;
1349 Location
[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
] = Thread
;
1351 Bits
[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE
+ 1] = 32;
1353 for ( LevelType
= CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
1354 ; LevelType
<= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE
+ 1
1357 if (Location
[LevelType
] != NULL
) {
1359 // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique
1360 // topology ID of the next level type.
1362 *Location
[LevelType
] = InitialApicId
>> Bits
[LevelType
- 1];
1365 // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.
1367 *Location
[LevelType
] &= (1 << (Bits
[LevelType
] - Bits
[LevelType
- 1])) - 1;