4 This local APIC library instance supports x2APIC capable processors
5 which have xAPIC and x2APIC modes.
7 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Register/Cpuid.h>
19 #include <Register/LocalApic.h>
21 #include <Library/BaseLib.h>
22 #include <Library/DebugLib.h>
23 #include <Library/LocalApicLib.h>
24 #include <Library/IoLib.h>
25 #include <Library/TimerLib.h>
26 #include <Library/PcdLib.h>
29 // Library internal functions
33 Determine if the CPU supports the Local APIC Base Address MSR.
35 @retval TRUE The CPU supports the Local APIC Base Address MSR.
36 @retval FALSE The CPU does not support the Local APIC Base Address MSR.
40 LocalApicBaseAddressMsrSupported (
47 AsmCpuid (1, &RegEax
, NULL
, NULL
, NULL
);
48 FamilyId
= BitFieldRead32 (RegEax
, 8, 11);
49 if (FamilyId
== 0x04 || FamilyId
== 0x05) {
51 // CPUs with a FamilyId of 0x04 or 0x05 do not support the
52 // Local APIC Base Address MSR
60 Retrieve the base address of local APIC.
62 @return The base address of local APIC.
67 GetLocalApicBaseAddress (
71 MSR_IA32_APIC_BASE ApicBaseMsr
;
73 if (!LocalApicBaseAddressMsrSupported ()) {
75 // If CPU does not support Local APIC Base Address MSR, then retrieve
76 // Local APIC Base Address from PCD
78 return PcdGet32 (PcdCpuLocalApicBaseAddress
);
81 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS
);
83 return (UINTN
)(LShiftU64 ((UINT64
) ApicBaseMsr
.Bits
.ApicBaseHigh
, 32)) +
84 (((UINTN
)ApicBaseMsr
.Bits
.ApicBaseLow
) << 12);
88 Set the base address of local APIC.
90 If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
92 @param[in] BaseAddress Local APIC base address to be set.
97 SetLocalApicBaseAddress (
101 MSR_IA32_APIC_BASE ApicBaseMsr
;
103 ASSERT ((BaseAddress
& (SIZE_4KB
- 1)) == 0);
105 if (!LocalApicBaseAddressMsrSupported ()) {
107 // Ignore set request of the CPU does not support APIC Base Address MSR
112 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS
);
114 ApicBaseMsr
.Bits
.ApicBaseLow
= (UINT32
) (BaseAddress
>> 12);
115 ApicBaseMsr
.Bits
.ApicBaseHigh
= (UINT32
) (RShiftU64((UINT64
) BaseAddress
, 32));
117 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS
, ApicBaseMsr
.Uint64
);
121 Read from a local APIC register.
123 This function reads from a local APIC register either in xAPIC or x2APIC mode.
124 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
125 accessed using multiple 32-bit loads or stores, so this function only performs
128 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
129 It must be 16-byte aligned.
131 @return 32-bit Value read from the register.
141 ASSERT ((MmioOffset
& 0xf) == 0);
143 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
144 return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset
);
147 // DFR is not supported in x2APIC mode.
149 ASSERT (MmioOffset
!= XAPIC_ICR_DFR_OFFSET
);
151 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
152 // is not supported in this function for simplicity.
154 ASSERT (MmioOffset
!= XAPIC_ICR_HIGH_OFFSET
);
156 MsrIndex
= (UINT32
)(MmioOffset
>> 4) + X2APIC_MSR_BASE_ADDRESS
;
157 return AsmReadMsr32 (MsrIndex
);
162 Write to a local APIC register.
164 This function writes to a local APIC register either in xAPIC or x2APIC mode.
165 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
166 accessed using multiple 32-bit loads or stores, so this function only performs
169 if the register index is invalid or unsupported in current APIC mode, then ASSERT.
171 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
172 It must be 16-byte aligned.
173 @param Value Value to be written to the register.
184 ASSERT ((MmioOffset
& 0xf) == 0);
186 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
187 MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset
, Value
);
190 // DFR is not supported in x2APIC mode.
192 ASSERT (MmioOffset
!= XAPIC_ICR_DFR_OFFSET
);
194 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
195 // is not supported in this function for simplicity.
197 ASSERT (MmioOffset
!= XAPIC_ICR_HIGH_OFFSET
);
198 ASSERT (MmioOffset
!= XAPIC_ICR_LOW_OFFSET
);
200 MsrIndex
= (UINT32
)(MmioOffset
>> 4) + X2APIC_MSR_BASE_ADDRESS
;
202 // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.
203 // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
206 AsmWriteMsr32 (MsrIndex
, Value
);
211 Send an IPI by writing to ICR.
213 This function returns after the IPI has been accepted by the target processor.
215 @param IcrLow 32-bit value to be written to the low half of ICR.
216 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
225 LOCAL_APIC_ICR_LOW IcrLowReg
;
226 UINTN LocalApciBaseAddress
;
228 BOOLEAN InterruptState
;
231 // Legacy APIC or X2APIC?
233 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
234 ASSERT (ApicId
<= 0xff);
236 InterruptState
= SaveAndDisableInterrupts ();
239 // Get base address of this LAPIC
241 LocalApciBaseAddress
= GetLocalApicBaseAddress();
244 // Save existing contents of ICR high 32 bits
246 IcrHigh
= MmioRead32 (LocalApciBaseAddress
+ XAPIC_ICR_HIGH_OFFSET
);
249 // Wait for DeliveryStatus clear in case a previous IPI
250 // is still being sent
253 IcrLowReg
.Uint32
= MmioRead32 (LocalApciBaseAddress
+ XAPIC_ICR_LOW_OFFSET
);
254 } while (IcrLowReg
.Bits
.DeliveryStatus
!= 0);
257 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
259 MmioWrite32 (LocalApciBaseAddress
+ XAPIC_ICR_HIGH_OFFSET
, ApicId
<< 24);
260 MmioWrite32 (LocalApciBaseAddress
+ XAPIC_ICR_LOW_OFFSET
, IcrLow
);
263 // Wait for DeliveryStatus clear again
266 IcrLowReg
.Uint32
= MmioRead32 (LocalApciBaseAddress
+ XAPIC_ICR_LOW_OFFSET
);
267 } while (IcrLowReg
.Bits
.DeliveryStatus
!= 0);
270 // And restore old contents of ICR high
272 MmioWrite32 (LocalApciBaseAddress
+ XAPIC_ICR_HIGH_OFFSET
, IcrHigh
);
274 SetInterruptState (InterruptState
);
278 // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
279 // interrupt in x2APIC mode.
281 MsrValue
= LShiftU64 ((UINT64
) ApicId
, 32) | IcrLow
;
282 AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS
, MsrValue
);
287 // Library API implementation functions
291 Get the current local APIC mode.
293 If local APIC is disabled, then ASSERT.
295 @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
296 @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
304 MSR_IA32_APIC_BASE ApicBaseMsr
;
306 if (!LocalApicBaseAddressMsrSupported ()) {
308 // If CPU does not support APIC Base Address MSR, then return XAPIC mode
310 return LOCAL_APIC_MODE_XAPIC
;
313 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS
);
315 // Local APIC should have been enabled
317 ASSERT (ApicBaseMsr
.Bits
.En
!= 0);
318 if (ApicBaseMsr
.Bits
.Extd
!= 0) {
319 return LOCAL_APIC_MODE_X2APIC
;
321 return LOCAL_APIC_MODE_XAPIC
;
326 Set the current local APIC mode.
328 If the specified local APIC mode is not valid, then ASSERT.
329 If the specified local APIC mode can't be set as current, then ASSERT.
331 @param ApicMode APIC mode to be set.
333 @note This API must not be called from an interrupt handler or SMI handler.
334 It may result in unpredictable behavior.
343 MSR_IA32_APIC_BASE ApicBaseMsr
;
345 if (!LocalApicBaseAddressMsrSupported ()) {
347 // Ignore set request if the CPU does not support APIC Base Address MSR
352 CurrentMode
= GetApicMode ();
353 if (CurrentMode
== LOCAL_APIC_MODE_XAPIC
) {
355 case LOCAL_APIC_MODE_XAPIC
:
357 case LOCAL_APIC_MODE_X2APIC
:
358 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS
);
359 ApicBaseMsr
.Bits
.Extd
= 1;
360 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS
, ApicBaseMsr
.Uint64
);
367 case LOCAL_APIC_MODE_XAPIC
:
369 // Transition from x2APIC mode to xAPIC mode is a two-step process:
370 // x2APIC -> Local APIC disabled -> xAPIC
372 ApicBaseMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS
);
373 ApicBaseMsr
.Bits
.Extd
= 0;
374 ApicBaseMsr
.Bits
.En
= 0;
375 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS
, ApicBaseMsr
.Uint64
);
376 ApicBaseMsr
.Bits
.En
= 1;
377 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS
, ApicBaseMsr
.Uint64
);
379 case LOCAL_APIC_MODE_X2APIC
:
388 Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
390 In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
391 In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
392 the 32-bit local APIC ID is returned as initial APIC ID.
394 @return 32-bit initial local APIC ID of the executing processor.
403 UINT32 MaxCpuIdIndex
;
406 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
408 // Get the max index of basic CPUID
410 AsmCpuid (CPUID_SIGNATURE
, &MaxCpuIdIndex
, NULL
, NULL
, NULL
);
412 // If CPUID Leaf B is supported,
413 // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
414 // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
416 if (MaxCpuIdIndex
>= CPUID_EXTENDED_TOPOLOGY
) {
417 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY
, 0, NULL
, NULL
, NULL
, &ApicId
);
420 AsmCpuid (CPUID_VERSION_INFO
, NULL
, &RegEbx
, NULL
, NULL
);
428 Get the local APIC ID of the executing processor.
430 @return 32-bit local APIC ID of the executing processor.
441 ApicId
= ReadLocalApicReg (XAPIC_ID_OFFSET
);
442 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC
) {
443 ApicId
= ((InitApicId
= GetInitialApicId ()) < 0x100) ? (ApicId
>> 24) : InitApicId
;
450 Get the value of the local APIC version register.
452 @return the value of the local APIC version register.
460 return ReadLocalApicReg (XAPIC_VERSION_OFFSET
);
464 Send a Fixed IPI to a specified target processor.
466 This function returns after the IPI has been accepted by the target processor.
468 @param ApicId The local APIC ID of the target processor.
469 @param Vector The vector number of the interrupt being sent.
478 LOCAL_APIC_ICR_LOW IcrLow
;
481 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_FIXED
;
482 IcrLow
.Bits
.Level
= 1;
483 IcrLow
.Bits
.Vector
= Vector
;
484 SendIpi (IcrLow
.Uint32
, ApicId
);
488 Send a Fixed IPI to all processors excluding self.
490 This function returns after the IPI has been accepted by the target processors.
492 @param Vector The vector number of the interrupt being sent.
496 SendFixedIpiAllExcludingSelf (
500 LOCAL_APIC_ICR_LOW IcrLow
;
503 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_FIXED
;
504 IcrLow
.Bits
.Level
= 1;
505 IcrLow
.Bits
.DestinationShorthand
= LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF
;
506 IcrLow
.Bits
.Vector
= Vector
;
507 SendIpi (IcrLow
.Uint32
, 0);
511 Send a SMI IPI to a specified target processor.
513 This function returns after the IPI has been accepted by the target processor.
515 @param ApicId Specify the local APIC ID of the target processor.
523 LOCAL_APIC_ICR_LOW IcrLow
;
526 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_SMI
;
527 IcrLow
.Bits
.Level
= 1;
528 SendIpi (IcrLow
.Uint32
, ApicId
);
532 Send a SMI IPI to all processors excluding self.
534 This function returns after the IPI has been accepted by the target processors.
538 SendSmiIpiAllExcludingSelf (
542 LOCAL_APIC_ICR_LOW IcrLow
;
545 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_SMI
;
546 IcrLow
.Bits
.Level
= 1;
547 IcrLow
.Bits
.DestinationShorthand
= LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF
;
548 SendIpi (IcrLow
.Uint32
, 0);
552 Send an INIT IPI to a specified target processor.
554 This function returns after the IPI has been accepted by the target processor.
556 @param ApicId Specify the local APIC ID of the target processor.
564 LOCAL_APIC_ICR_LOW IcrLow
;
567 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_INIT
;
568 IcrLow
.Bits
.Level
= 1;
569 SendIpi (IcrLow
.Uint32
, ApicId
);
573 Send an INIT IPI to all processors excluding self.
575 This function returns after the IPI has been accepted by the target processors.
579 SendInitIpiAllExcludingSelf (
583 LOCAL_APIC_ICR_LOW IcrLow
;
586 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_INIT
;
587 IcrLow
.Bits
.Level
= 1;
588 IcrLow
.Bits
.DestinationShorthand
= LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF
;
589 SendIpi (IcrLow
.Uint32
, 0);
593 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
595 This function returns after the IPI has been accepted by the target processor.
597 if StartupRoutine >= 1M, then ASSERT.
598 if StartupRoutine is not multiple of 4K, then ASSERT.
600 @param ApicId Specify the local APIC ID of the target processor.
601 @param StartupRoutine Points to a start-up routine which is below 1M physical
602 address and 4K aligned.
608 IN UINT32 StartupRoutine
611 LOCAL_APIC_ICR_LOW IcrLow
;
613 ASSERT (StartupRoutine
< 0x100000);
614 ASSERT ((StartupRoutine
& 0xfff) == 0);
616 SendInitIpi (ApicId
);
617 MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds
));
619 IcrLow
.Bits
.Vector
= (StartupRoutine
>> 12);
620 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_STARTUP
;
621 IcrLow
.Bits
.Level
= 1;
622 SendIpi (IcrLow
.Uint32
, ApicId
);
623 MicroSecondDelay (200);
624 SendIpi (IcrLow
.Uint32
, ApicId
);
628 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
630 This function returns after the IPI has been accepted by the target processors.
632 if StartupRoutine >= 1M, then ASSERT.
633 if StartupRoutine is not multiple of 4K, then ASSERT.
635 @param StartupRoutine Points to a start-up routine which is below 1M physical
636 address and 4K aligned.
640 SendInitSipiSipiAllExcludingSelf (
641 IN UINT32 StartupRoutine
644 LOCAL_APIC_ICR_LOW IcrLow
;
646 ASSERT (StartupRoutine
< 0x100000);
647 ASSERT ((StartupRoutine
& 0xfff) == 0);
649 SendInitIpiAllExcludingSelf ();
650 MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds
));
652 IcrLow
.Bits
.Vector
= (StartupRoutine
>> 12);
653 IcrLow
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_STARTUP
;
654 IcrLow
.Bits
.Level
= 1;
655 IcrLow
.Bits
.DestinationShorthand
= LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF
;
656 SendIpi (IcrLow
.Uint32
, 0);
657 MicroSecondDelay (200);
658 SendIpi (IcrLow
.Uint32
, 0);
662 Initialize the state of the SoftwareEnable bit in the Local APIC
663 Spurious Interrupt Vector register.
665 @param Enable If TRUE, then set SoftwareEnable to 1
666 If FALSE, then set SoftwareEnable to 0.
671 InitializeLocalApicSoftwareEnable (
678 // Set local APIC software-enabled bit.
680 Svr
.Uint32
= ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
);
682 if (Svr
.Bits
.SoftwareEnable
== 0) {
683 Svr
.Bits
.SoftwareEnable
= 1;
684 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
, Svr
.Uint32
);
687 if (Svr
.Bits
.SoftwareEnable
== 1) {
688 Svr
.Bits
.SoftwareEnable
= 0;
689 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
, Svr
.Uint32
);
695 Programming Virtual Wire Mode.
697 This function programs the local APIC for virtual wire mode following
698 the example described in chapter A.3 of the MP 1.4 spec.
700 IOxAPIC is not involved in this type of virtual wire mode.
704 ProgramVirtualWireMode (
709 LOCAL_APIC_LVT_LINT Lint
;
712 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
714 Svr
.Uint32
= ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
);
715 Svr
.Bits
.SpuriousVector
= 0xf;
716 Svr
.Bits
.SoftwareEnable
= 1;
717 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
, Svr
.Uint32
);
720 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
722 Lint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET
);
723 Lint
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_EXTINT
;
724 Lint
.Bits
.InputPinPolarity
= 0;
725 Lint
.Bits
.TriggerMode
= 0;
727 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET
, Lint
.Uint32
);
730 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
732 Lint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET
);
733 Lint
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_NMI
;
734 Lint
.Bits
.InputPinPolarity
= 0;
735 Lint
.Bits
.TriggerMode
= 0;
737 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET
, Lint
.Uint32
);
741 Disable LINT0 & LINT1 interrupts.
743 This function sets the mask flag in the LVT LINT0 & LINT1 registers.
747 DisableLvtInterrupts (
751 LOCAL_APIC_LVT_LINT LvtLint
;
753 LvtLint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET
);
754 LvtLint
.Bits
.Mask
= 1;
755 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET
, LvtLint
.Uint32
);
757 LvtLint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET
);
758 LvtLint
.Bits
.Mask
= 1;
759 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET
, LvtLint
.Uint32
);
763 Read the initial count value from the init-count register.
765 @return The initial count value read from the init-count register.
769 GetApicTimerInitCount (
773 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET
);
777 Read the current count value from the current-count register.
779 @return The current count value read from the current-count register.
783 GetApicTimerCurrentCount (
787 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET
);
791 Initialize the local APIC timer.
793 The local APIC timer is initialized and enabled.
795 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
796 If it is 0, then use the current divide value in the DCR.
797 @param InitCount The initial count value.
798 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
799 @param Vector The timer interrupt vector number.
803 InitializeApicTimer (
804 IN UINTN DivideValue
,
806 IN BOOLEAN PeriodicMode
,
811 LOCAL_APIC_LVT_TIMER LvtTimer
;
815 // Ensure local APIC is in software-enabled state.
817 InitializeLocalApicSoftwareEnable (TRUE
);
820 // Program init-count register.
822 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET
, InitCount
);
824 if (DivideValue
!= 0) {
825 ASSERT (DivideValue
<= 128);
826 ASSERT (DivideValue
== GetPowerOfTwo32((UINT32
)DivideValue
));
827 Divisor
= (UINT32
)((HighBitSet32 ((UINT32
)DivideValue
) - 1) & 0x7);
829 Dcr
.Uint32
= ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
);
830 Dcr
.Bits
.DivideValue1
= (Divisor
& 0x3);
831 Dcr
.Bits
.DivideValue2
= (Divisor
>> 2);
832 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
, Dcr
.Uint32
);
836 // Enable APIC timer interrupt with specified timer mode.
838 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
840 LvtTimer
.Bits
.TimerMode
= 1;
842 LvtTimer
.Bits
.TimerMode
= 0;
844 LvtTimer
.Bits
.Mask
= 0;
845 LvtTimer
.Bits
.Vector
= Vector
;
846 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
850 Get the state of the local APIC timer.
852 This function will ASSERT if the local APIC is not software enabled.
854 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
855 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
856 @param Vector Return the timer interrupt vector number.
861 OUT UINTN
*DivideValue OPTIONAL
,
862 OUT BOOLEAN
*PeriodicMode OPTIONAL
,
863 OUT UINT8
*Vector OPTIONAL
868 LOCAL_APIC_LVT_TIMER LvtTimer
;
871 // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
873 // This bit will be 1, if local APIC is software enabled.
875 ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET
) & BIT8
) != 0);
877 if (DivideValue
!= NULL
) {
878 Dcr
.Uint32
= ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
);
879 Divisor
= Dcr
.Bits
.DivideValue1
| (Dcr
.Bits
.DivideValue2
<< 2);
880 Divisor
= (Divisor
+ 1) & 0x7;
881 *DivideValue
= ((UINTN
)1) << Divisor
;
884 if (PeriodicMode
!= NULL
|| Vector
!= NULL
) {
885 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
886 if (PeriodicMode
!= NULL
) {
887 if (LvtTimer
.Bits
.TimerMode
== 1) {
888 *PeriodicMode
= TRUE
;
890 *PeriodicMode
= FALSE
;
893 if (Vector
!= NULL
) {
894 *Vector
= (UINT8
) LvtTimer
.Bits
.Vector
;
900 Enable the local APIC timer interrupt.
904 EnableApicTimerInterrupt (
908 LOCAL_APIC_LVT_TIMER LvtTimer
;
910 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
911 LvtTimer
.Bits
.Mask
= 0;
912 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
916 Disable the local APIC timer interrupt.
920 DisableApicTimerInterrupt (
924 LOCAL_APIC_LVT_TIMER LvtTimer
;
926 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
927 LvtTimer
.Bits
.Mask
= 1;
928 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
932 Get the local APIC timer interrupt state.
934 @retval TRUE The local APIC timer interrupt is enabled.
935 @retval FALSE The local APIC timer interrupt is disabled.
939 GetApicTimerInterruptState (
943 LOCAL_APIC_LVT_TIMER LvtTimer
;
945 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
946 return (BOOLEAN
)(LvtTimer
.Bits
.Mask
== 0);
950 Send EOI to the local APIC.
958 WriteLocalApicReg (XAPIC_EOI_OFFSET
, 0);
962 Get the 32-bit address that a device should use to send a Message Signaled
963 Interrupt (MSI) to the Local APIC of the currently executing processor.
965 @return 32-bit address used to send an MSI to the Local APIC.
973 LOCAL_APIC_MSI_ADDRESS MsiAddress
;
976 // Return address for an MSI interrupt to be delivered only to the APIC ID
977 // of the currently executing processor.
979 MsiAddress
.Uint32
= 0;
980 MsiAddress
.Bits
.BaseAddress
= 0xFEE;
981 MsiAddress
.Bits
.DestinationId
= GetApicId ();
982 return MsiAddress
.Uint32
;
986 Get the 64-bit data value that a device should use to send a Message Signaled
987 Interrupt (MSI) to the Local APIC of the currently executing processor.
989 If Vector is not in range 0x10..0xFE, then ASSERT().
990 If DeliveryMode is not supported, then ASSERT().
992 @param Vector The 8-bit interrupt vector associated with the MSI.
993 Must be in the range 0x10..0xFE
994 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
995 is handled. The only supported values are:
996 0: LOCAL_APIC_DELIVERY_MODE_FIXED
997 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
998 2: LOCAL_APIC_DELIVERY_MODE_SMI
999 4: LOCAL_APIC_DELIVERY_MODE_NMI
1000 5: LOCAL_APIC_DELIVERY_MODE_INIT
1001 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
1003 @param LevelTriggered TRUE specifies a level triggered interrupt.
1004 FALSE specifies an edge triggered interrupt.
1005 @param AssertionLevel Ignored if LevelTriggered is FALSE.
1006 TRUE specifies a level triggered interrupt that active
1007 when the interrupt line is asserted.
1008 FALSE specifies a level triggered interrupt that active
1009 when the interrupt line is deasserted.
1011 @return 64-bit data value used to send an MSI to the Local APIC.
1017 IN UINTN DeliveryMode
,
1018 IN BOOLEAN LevelTriggered
,
1019 IN BOOLEAN AssertionLevel
1022 LOCAL_APIC_MSI_DATA MsiData
;
1024 ASSERT (Vector
>= 0x10 && Vector
<= 0xFE);
1025 ASSERT (DeliveryMode
< 8 && DeliveryMode
!= 6 && DeliveryMode
!= 3);
1028 MsiData
.Bits
.Vector
= Vector
;
1029 MsiData
.Bits
.DeliveryMode
= (UINT32
)DeliveryMode
;
1030 if (LevelTriggered
) {
1031 MsiData
.Bits
.TriggerMode
= 1;
1032 if (AssertionLevel
) {
1033 MsiData
.Bits
.Level
= 1;
1036 return MsiData
.Uint64
;