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 Programming Virtual Wire Mode.
664 This function programs the local APIC for virtual wire mode following
665 the example described in chapter A.3 of the MP 1.4 spec.
667 IOxAPIC is not involved in this type of virtual wire mode.
671 ProgramVirtualWireMode (
676 LOCAL_APIC_LVT_LINT Lint
;
679 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
681 Svr
.Uint32
= ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
);
682 Svr
.Bits
.SpuriousVector
= 0xf;
683 Svr
.Bits
.SoftwareEnable
= 1;
684 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
, Svr
.Uint32
);
687 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
689 Lint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET
);
690 Lint
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_EXTINT
;
691 Lint
.Bits
.InputPinPolarity
= 0;
692 Lint
.Bits
.TriggerMode
= 0;
694 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET
, Lint
.Uint32
);
697 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
699 Lint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET
);
700 Lint
.Bits
.DeliveryMode
= LOCAL_APIC_DELIVERY_MODE_NMI
;
701 Lint
.Bits
.InputPinPolarity
= 0;
702 Lint
.Bits
.TriggerMode
= 0;
704 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET
, Lint
.Uint32
);
708 Disable LINT0 & LINT1 interrupts.
710 This function sets the mask flag in the LVT LINT0 & LINT1 registers.
714 DisableLvtInterrupts (
718 LOCAL_APIC_LVT_LINT LvtLint
;
720 LvtLint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET
);
721 LvtLint
.Bits
.Mask
= 1;
722 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET
, LvtLint
.Uint32
);
724 LvtLint
.Uint32
= ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET
);
725 LvtLint
.Bits
.Mask
= 1;
726 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET
, LvtLint
.Uint32
);
730 Read the initial count value from the init-count register.
732 @return The initial count value read from the init-count register.
736 GetApicTimerInitCount (
740 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET
);
744 Read the current count value from the current-count register.
746 @return The current count value read from the current-count register.
750 GetApicTimerCurrentCount (
754 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET
);
758 Initialize the local APIC timer.
760 The local APIC timer is initialized and enabled.
762 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
763 If it is 0, then use the current divide value in the DCR.
764 @param InitCount The initial count value.
765 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
766 @param Vector The timer interrupt vector number.
770 InitializeApicTimer (
771 IN UINTN DivideValue
,
773 IN BOOLEAN PeriodicMode
,
779 LOCAL_APIC_LVT_TIMER LvtTimer
;
783 // Ensure local APIC is in software-enabled state.
785 Svr
.Uint32
= ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
);
786 Svr
.Bits
.SoftwareEnable
= 1;
787 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET
, Svr
.Uint32
);
790 // Program init-count register.
792 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET
, InitCount
);
794 if (DivideValue
!= 0) {
795 ASSERT (DivideValue
<= 128);
796 ASSERT (DivideValue
== GetPowerOfTwo32((UINT32
)DivideValue
));
797 Divisor
= (UINT32
)((HighBitSet32 ((UINT32
)DivideValue
) - 1) & 0x7);
799 Dcr
.Uint32
= ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
);
800 Dcr
.Bits
.DivideValue1
= (Divisor
& 0x3);
801 Dcr
.Bits
.DivideValue2
= (Divisor
>> 2);
802 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
, Dcr
.Uint32
);
806 // Enable APIC timer interrupt with specified timer mode.
808 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
810 LvtTimer
.Bits
.TimerMode
= 1;
812 LvtTimer
.Bits
.TimerMode
= 0;
814 LvtTimer
.Bits
.Mask
= 0;
815 LvtTimer
.Bits
.Vector
= Vector
;
816 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
820 Get the state of the local APIC timer.
822 This function will ASSERT if the local APIC is not software enabled.
824 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
825 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
826 @param Vector Return the timer interrupt vector number.
831 OUT UINTN
*DivideValue OPTIONAL
,
832 OUT BOOLEAN
*PeriodicMode OPTIONAL
,
833 OUT UINT8
*Vector OPTIONAL
838 LOCAL_APIC_LVT_TIMER LvtTimer
;
841 // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
843 // This bit will be 1, if local APIC is software enabled.
845 ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET
) & BIT8
) != 0);
847 if (DivideValue
!= NULL
) {
848 Dcr
.Uint32
= ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET
);
849 Divisor
= Dcr
.Bits
.DivideValue1
| (Dcr
.Bits
.DivideValue2
<< 2);
850 Divisor
= (Divisor
+ 1) & 0x7;
851 *DivideValue
= ((UINTN
)1) << Divisor
;
854 if (PeriodicMode
!= NULL
|| Vector
!= NULL
) {
855 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
856 if (PeriodicMode
!= NULL
) {
857 if (LvtTimer
.Bits
.TimerMode
== 1) {
858 *PeriodicMode
= TRUE
;
860 *PeriodicMode
= FALSE
;
863 if (Vector
!= NULL
) {
864 *Vector
= (UINT8
) LvtTimer
.Bits
.Vector
;
870 Enable the local APIC timer interrupt.
874 EnableApicTimerInterrupt (
878 LOCAL_APIC_LVT_TIMER LvtTimer
;
880 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
881 LvtTimer
.Bits
.Mask
= 0;
882 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
886 Disable the local APIC timer interrupt.
890 DisableApicTimerInterrupt (
894 LOCAL_APIC_LVT_TIMER LvtTimer
;
896 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
897 LvtTimer
.Bits
.Mask
= 1;
898 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET
, LvtTimer
.Uint32
);
902 Get the local APIC timer interrupt state.
904 @retval TRUE The local APIC timer interrupt is enabled.
905 @retval FALSE The local APIC timer interrupt is disabled.
909 GetApicTimerInterruptState (
913 LOCAL_APIC_LVT_TIMER LvtTimer
;
915 LvtTimer
.Uint32
= ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET
);
916 return (BOOLEAN
)(LvtTimer
.Bits
.Mask
== 0);
920 Send EOI to the local APIC.
928 WriteLocalApicReg (XAPIC_EOI_OFFSET
, 0);
932 Get the 32-bit address that a device should use to send a Message Signaled
933 Interrupt (MSI) to the Local APIC of the currently executing processor.
935 @return 32-bit address used to send an MSI to the Local APIC.
943 LOCAL_APIC_MSI_ADDRESS MsiAddress
;
946 // Return address for an MSI interrupt to be delivered only to the APIC ID
947 // of the currently executing processor.
949 MsiAddress
.Uint32
= 0;
950 MsiAddress
.Bits
.BaseAddress
= 0xFEE;
951 MsiAddress
.Bits
.DestinationId
= GetApicId ();
952 return MsiAddress
.Uint32
;
956 Get the 64-bit data value that a device should use to send a Message Signaled
957 Interrupt (MSI) to the Local APIC of the currently executing processor.
959 If Vector is not in range 0x10..0xFE, then ASSERT().
960 If DeliveryMode is not supported, then ASSERT().
962 @param Vector The 8-bit interrupt vector associated with the MSI.
963 Must be in the range 0x10..0xFE
964 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
965 is handled. The only supported values are:
966 0: LOCAL_APIC_DELIVERY_MODE_FIXED
967 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
968 2: LOCAL_APIC_DELIVERY_MODE_SMI
969 4: LOCAL_APIC_DELIVERY_MODE_NMI
970 5: LOCAL_APIC_DELIVERY_MODE_INIT
971 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
973 @param LevelTriggered TRUE specifies a level triggered interrupt.
974 FALSE specifies an edge triggered interrupt.
975 @param AssertionLevel Ignored if LevelTriggered is FALSE.
976 TRUE specifies a level triggered interrupt that active
977 when the interrupt line is asserted.
978 FALSE specifies a level triggered interrupt that active
979 when the interrupt line is deasserted.
981 @return 64-bit data value used to send an MSI to the Local APIC.
987 IN UINTN DeliveryMode
,
988 IN BOOLEAN LevelTriggered
,
989 IN BOOLEAN AssertionLevel
992 LOCAL_APIC_MSI_DATA MsiData
;
994 ASSERT (Vector
>= 0x10 && Vector
<= 0xFE);
995 ASSERT (DeliveryMode
< 8 && DeliveryMode
!= 6 && DeliveryMode
!= 3);
998 MsiData
.Bits
.Vector
= Vector
;
999 MsiData
.Bits
.DeliveryMode
= (UINT32
)DeliveryMode
;
1000 if (LevelTriggered
) {
1001 MsiData
.Bits
.TriggerMode
= 1;
1002 if (AssertionLevel
) {
1003 MsiData
.Bits
.Level
= 1;
1006 return MsiData
.Uint64
;