+/** @file\r
+ Local APIC Library.\r
+\r
+ This local APIC library instance supports x2APIC capable processors\r
+ which have xAPIC and x2APIC modes.\r
+\r
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Register/LocalApic.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/LocalApicLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+//\r
+// Library internal functions\r
+//\r
+\r
+/**\r
+ Read from a local APIC register.\r
+\r
+ This function reads from a local APIC register either in xAPIC or x2APIC mode.\r
+ It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be\r
+ accessed using multiple 32-bit loads or stores, so this function only performs\r
+ 32-bit read.\r
+\r
+ @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.\r
+ It must be 16-byte aligned.\r
+\r
+ @return 32-bit Value read from the register.\r
+**/\r
+UINT32\r
+EFIAPI\r
+ReadLocalApicReg (\r
+ IN UINTN MmioOffset\r
+ )\r
+{\r
+ UINT32 MsrIndex;\r
+\r
+ ASSERT ((MmioOffset & 0xf) == 0);\r
+\r
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
+ return MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset);\r
+ } else {\r
+ //\r
+ // DFR is not supported in x2APIC mode.\r
+ //\r
+ ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);\r
+ //\r
+ // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It\r
+ // is not supported in this function for simplicity.\r
+ //\r
+ ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
+\r
+ MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
+ return AsmReadMsr32 (MsrIndex);\r
+ }\r
+}\r
+\r
+/**\r
+ Write to a local APIC register.\r
+\r
+ This function writes to a local APIC register either in xAPIC or x2APIC mode.\r
+ It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be\r
+ accessed using multiple 32-bit loads or stores, so this function only performs\r
+ 32-bit write.\r
+\r
+ if the register index is invalid or unsupported in current APIC mode, then ASSERT.\r
+\r
+ @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.\r
+ It must be 16-byte aligned.\r
+ @param Value Value to be written to the register.\r
+**/\r
+VOID\r
+EFIAPI\r
+WriteLocalApicReg (\r
+ IN UINTN MmioOffset,\r
+ IN UINT32 Value\r
+ )\r
+{\r
+ UINT32 MsrIndex;\r
+\r
+ ASSERT ((MmioOffset & 0xf) == 0);\r
+\r
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
+ MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + MmioOffset, Value);\r
+ } else {\r
+ //\r
+ // DFR is not supported in x2APIC mode.\r
+ //\r
+ ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);\r
+ //\r
+ // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It\r
+ // is not supported in this function for simplicity.\r
+ //\r
+ ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);\r
+ ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);\r
+\r
+ MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;\r
+ //\r
+ // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.\r
+ // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.\r
+ //\r
+ MemoryFence ();\r
+ AsmWriteMsr32 (MsrIndex, Value);\r
+ }\r
+}\r
+\r
+/**\r
+ Send an IPI by writing to ICR.\r
+\r
+ This function returns after the IPI has been accepted by the target processor. \r
+\r
+ @param IcrLow 32-bit value to be written to the low half of ICR.\r
+ @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.\r
+**/\r
+VOID\r
+SendIpi (\r
+ IN UINT32 IcrLow,\r
+ IN UINT32 ApicId\r
+ )\r
+{\r
+ UINT64 MsrValue;\r
+ LOCAL_APIC_ICR_LOW IcrLowReg;\r
+\r
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
+ ASSERT (ApicId <= 0xff);\r
+\r
+ //\r
+ // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.\r
+ //\r
+ MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
+ MmioWrite32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_LOW_OFFSET, IcrLow);\r
+ do {\r
+ IcrLowReg.Uint32 = MmioRead32 (PcdGet32 (PcdCpuLocalApicBaseAddress) + XAPIC_ICR_LOW_OFFSET);\r
+ } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
+ } else {\r
+ //\r
+ // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an \r
+ // interrupt in x2APIC mode.\r
+ //\r
+ MsrValue = (((UINT64)ApicId) << 32) | IcrLow;\r
+ AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);\r
+ }\r
+}\r
+\r
+//\r
+// Library API implementation functions\r
+//\r
+\r
+/**\r
+ Get the current local APIC mode.\r
+\r
+ If local APIC is disabled, then ASSERT.\r
+\r
+ @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.\r
+ @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.\r
+**/\r
+UINTN\r
+EFIAPI\r
+GetApicMode (\r
+ VOID\r
+ )\r
+{\r
+ MSR_IA32_APIC_BASE ApicBaseMsr;\r
+\r
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
+ //\r
+ // Local APIC should have been enabled\r
+ //\r
+ ASSERT (ApicBaseMsr.Bits.En != 0);\r
+ if (ApicBaseMsr.Bits.Extd != 0) {\r
+ return LOCAL_APIC_MODE_X2APIC;\r
+ } else {\r
+ return LOCAL_APIC_MODE_XAPIC;\r
+ }\r
+}\r
+\r
+/**\r
+ Set the current local APIC mode.\r
+\r
+ If the specified local APIC mode is not valid, then ASSERT.\r
+ If the specified local APIC mode can't be set as current, then ASSERT.\r
+\r
+ @param ApicMode APIC mode to be set.\r
+**/\r
+VOID\r
+EFIAPI\r
+SetApicMode (\r
+ IN UINTN ApicMode\r
+ )\r
+{\r
+ UINTN CurrentMode;\r
+ MSR_IA32_APIC_BASE ApicBaseMsr;\r
+\r
+ CurrentMode = GetApicMode ();\r
+ if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {\r
+ switch (ApicMode) {\r
+ case LOCAL_APIC_MODE_XAPIC:\r
+ break;\r
+ case LOCAL_APIC_MODE_X2APIC:\r
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
+ ApicBaseMsr.Bits.Extd = 1;\r
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+ } else {\r
+ switch (ApicMode) {\r
+ case LOCAL_APIC_MODE_XAPIC:\r
+ //\r
+ // Transition from x2APIC mode to xAPIC mode is a two-step process:\r
+ // x2APIC -> Local APIC disabled -> xAPIC\r
+ //\r
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);\r
+ ApicBaseMsr.Bits.Extd = 0;\r
+ ApicBaseMsr.Bits.En = 0;\r
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
+ ApicBaseMsr.Bits.En = 1;\r
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);\r
+ break;\r
+ case LOCAL_APIC_MODE_X2APIC:\r
+ break;\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.\r
+\r
+ In xAPIC mode, the initial local APIC ID is 8-bit, and may be different from current APIC ID.\r
+ In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case, \r
+ the 32-bit local APIC ID is returned as initial APIC ID.\r
+\r
+ @return 32-bit initial local APIC ID of the executing processor.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetInitialApicId (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegEbx;\r
+\r
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
+ AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);\r
+ return RegEbx >> 24;\r
+ } else {\r
+ return GetApicId ();\r
+ }\r
+}\r
+\r
+/**\r
+ Get the local APIC ID of the executing processor.\r
+\r
+ @return 32-bit local APIC ID of the executing processor.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetApicId (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 ApicId;\r
+\r
+ ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);\r
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
+ ApicId >>= 24;\r
+ }\r
+ return ApicId;\r
+}\r
+\r
+/**\r
+ Send a SMI IPI to a specified target processor.\r
+\r
+ This function returns after the IPI has been accepted by the target processor. \r
+\r
+ @param ApicId Specify the local APIC ID of the target processor.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendSmiIpi (\r
+ IN UINT32 ApicId\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
+ IcrLow.Bits.Level = 1;\r
+ SendIpi (IcrLow.Uint32, ApicId);\r
+}\r
+\r
+/**\r
+ Send a SMI IPI to all processors excluding self.\r
+\r
+ This function returns after the IPI has been accepted by the target processors. \r
+**/\r
+VOID\r
+EFIAPI\r
+SendSmiIpiAllExcludingSelf (\r
+ VOID\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;\r
+ IcrLow.Bits.Level = 1;\r
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
+ SendIpi (IcrLow.Uint32, 0);\r
+}\r
+\r
+/**\r
+ Send an INIT IPI to a specified target processor.\r
+\r
+ This function returns after the IPI has been accepted by the target processor. \r
+\r
+ @param ApicId Specify the local APIC ID of the target processor.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendInitIpi (\r
+ IN UINT32 ApicId\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
+ IcrLow.Bits.Level = 1;\r
+ SendIpi (IcrLow.Uint32, ApicId);\r
+}\r
+\r
+/**\r
+ Send an INIT IPI to all processors excluding self.\r
+\r
+ This function returns after the IPI has been accepted by the target processors. \r
+**/\r
+VOID\r
+EFIAPI\r
+SendInitIpiAllExcludingSelf (\r
+ VOID\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;\r
+ IcrLow.Bits.Level = 1;\r
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
+ SendIpi (IcrLow.Uint32, 0);\r
+}\r
+\r
+/**\r
+ Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.\r
+\r
+ This function returns after the IPI has been accepted by the target processor. \r
+\r
+ if StartupRoutine >= 1M, then ASSERT.\r
+ if StartupRoutine is not multiple of 4K, then ASSERT.\r
+\r
+ @param ApicId Specify the local APIC ID of the target processor.\r
+ @param StartupRoutine Points to a start-up routine which is below 1M physical\r
+ address and 4K aligned.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendInitSipiSipi (\r
+ IN UINT32 ApicId,\r
+ IN UINT32 StartupRoutine\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ ASSERT (StartupRoutine < 0x100000);\r
+ ASSERT ((StartupRoutine & 0xfff) == 0);\r
+\r
+ SendInitIpi (ApicId);\r
+ MicroSecondDelay (10);\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
+ IcrLow.Bits.Level = 1;\r
+ SendIpi (IcrLow.Uint32, ApicId);\r
+ MicroSecondDelay (200);\r
+ SendIpi (IcrLow.Uint32, ApicId);\r
+}\r
+\r
+/**\r
+ Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.\r
+\r
+ This function returns after the IPI has been accepted by the target processors. \r
+\r
+ if StartupRoutine >= 1M, then ASSERT.\r
+ if StartupRoutine is not multiple of 4K, then ASSERT.\r
+\r
+ @param StartupRoutine Points to a start-up routine which is below 1M physical\r
+ address and 4K aligned.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendInitSipiSipiAllExcludingSelf (\r
+ IN UINT32 StartupRoutine\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ ASSERT (StartupRoutine < 0x100000);\r
+ ASSERT ((StartupRoutine & 0xfff) == 0);\r
+\r
+ SendInitIpiAllExcludingSelf ();\r
+ MicroSecondDelay (10);\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.Vector = (StartupRoutine >> 12);\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;\r
+ IcrLow.Bits.Level = 1;\r
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
+ SendIpi (IcrLow.Uint32, 0);\r
+ MicroSecondDelay (200);\r
+ SendIpi (IcrLow.Uint32, 0);\r
+}\r
+\r
+/**\r
+ Programming Virtual Wire Mode.\r
+\r
+ This function programs the local APIC for virtual wire mode following\r
+ the example described in chapter A.3 of the MP 1.4 spec.\r
+\r
+ IOxAPIC is not involved in this type of virtual wire mode.\r
+**/\r
+VOID\r
+EFIAPI\r
+ProgramVirtualWireMode (\r
+ VOID\r
+ )\r
+{\r
+ LOCAL_APIC_SVR Svr;\r
+ LOCAL_APIC_LVT_LINT Lint;\r
+\r
+ //\r
+ // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.\r
+ //\r
+ Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
+ Svr.Bits.SpuriousVector = 0xf;\r
+ Svr.Bits.SoftwareEnable = 1;\r
+ WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
+\r
+ //\r
+ // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.\r
+ //\r
+ Lint.Uint32 = ReadLocalApicReg (XAPIC_LINT0_VECTOR_OFFSET);\r
+ Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;\r
+ Lint.Bits.InputPinPolarity = 0;\r
+ Lint.Bits.TriggerMode = 0;\r
+ Lint.Bits.Mask = 0;\r
+ WriteLocalApicReg (XAPIC_LINT0_VECTOR_OFFSET, Lint.Uint32);\r
+\r
+ //\r
+ // Program the LINT0 vector entry as NMI. Not masked, edge, active high.\r
+ //\r
+ Lint.Uint32 = ReadLocalApicReg (XAPIC_LINT1_VECTOR_OFFSET);\r
+ Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;\r
+ Lint.Bits.InputPinPolarity = 0;\r
+ Lint.Bits.TriggerMode = 0;\r
+ Lint.Bits.Mask = 0;\r
+ WriteLocalApicReg (XAPIC_LINT1_VECTOR_OFFSET, Lint.Uint32);\r
+}\r
+\r
+/**\r
+ Get the divide value from the DCR (Divide Configuration Register) by which\r
+ the processor's bus clock is divided to form the time base for the APIC timer.\r
+\r
+ @return The divide value is one of 1,2,4,8,16,32,64,128.\r
+**/\r
+UINTN\r
+EFIAPI\r
+GetApicTimerDivisor (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 DivideValue;\r
+ LOCAL_APIC_DCR Dcr;\r
+\r
+ Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
+ DivideValue = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
+ DivideValue = (DivideValue + 1) & 0x7;\r
+ return ((UINTN)1) << DivideValue;\r
+}\r
+\r
+/**\r
+ Read the initial count value from the init-count register.\r
+\r
+ @return The initial count value read from the init-count register.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetApicTimerInitCount (\r
+ VOID\r
+ )\r
+{\r
+ return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);\r
+}\r
+\r
+/**\r
+ Read the current count value from the current-count register.\r
+\r
+ @return The current count value read from the current-count register.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetApicTimerCurrentCount (\r
+ VOID\r
+ )\r
+{\r
+ return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);\r
+}\r
+\r
+/**\r
+ Initialize the local APIC timer.\r
+\r
+ The local APIC timer is initialized and enabled.\r
+\r
+ @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
+ If it is 0, then use the current divide value in the DCR.\r
+ @param InitCount The initial count value.\r
+ @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
+ @param Vector The timer interrupt vector number.\r
+**/\r
+VOID\r
+EFIAPI\r
+InitializeApicTimer (\r
+ IN UINTN DivideValue,\r
+ IN UINT32 InitCount,\r
+ IN BOOLEAN PeriodicMode,\r
+ IN UINT8 Vector\r
+ )\r
+{\r
+ LOCAL_APIC_SVR Svr;\r
+ LOCAL_APIC_DCR Dcr;\r
+ LOCAL_APIC_LVT_TIMER LvtTimer;\r
+ UINT32 Divisor;\r
+\r
+ //\r
+ // Ensure local APIC is in software-enabled state.\r
+ //\r
+ Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);\r
+ Svr.Bits.SoftwareEnable = 1;\r
+ WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);\r
+\r
+ //\r
+ // Program init-count register.\r
+ //\r
+ WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);\r
+\r
+ if (DivideValue != 0) {\r
+ ASSERT (DivideValue <= 128);\r
+ ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));\r
+ Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);\r
+\r
+ Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
+ Dcr.Bits.DivideValue1 = (Divisor & 0x3);\r
+ Dcr.Bits.DivideValue2 = (Divisor >> 2);\r
+ WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32); \r
+ }\r
+\r
+ //\r
+ // Enable APIC timer interrupt with specified timer mode.\r
+ //\r
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
+ if (PeriodicMode) {\r
+ LvtTimer.Bits.TimerMode = 1;\r
+ } else {\r
+ LvtTimer.Bits.TimerMode = 0;\r
+ }\r
+ LvtTimer.Bits.Mask = 0;\r
+ LvtTimer.Bits.Vector = Vector;\r
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
+}\r
+\r
+/**\r
+ Enable the local APIC timer interrupt.\r
+**/\r
+VOID\r
+EFIAPI\r
+EnableApicTimerInterrupt (\r
+ VOID\r
+ )\r
+{\r
+ LOCAL_APIC_LVT_TIMER LvtTimer;\r
+\r
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
+ LvtTimer.Bits.Mask = 0;\r
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
+}\r
+\r
+/**\r
+ Disable the local APIC timer interrupt.\r
+**/\r
+VOID\r
+EFIAPI\r
+DisableApicTimerInterrupt (\r
+ VOID\r
+ )\r
+{\r
+ LOCAL_APIC_LVT_TIMER LvtTimer;\r
+\r
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
+ LvtTimer.Bits.Mask = 1;\r
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
+}\r
+\r
+/**\r
+ Get the local APIC timer interrupt state.\r
+\r
+ @retval TRUE The local APIC timer interrupt is enabled.\r
+ @retval FALSE The local APIC timer interrupt is disabled.\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+GetApicTimerInterruptState (\r
+ VOID\r
+ )\r
+{\r
+ LOCAL_APIC_LVT_TIMER LvtTimer;\r
+\r
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
+ return (BOOLEAN)(LvtTimer.Bits.Mask == 0);\r
+}\r
+\r
+/**\r
+ Send EOI to the local APIC.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendApicEoi (\r
+ VOID\r
+ )\r
+{\r
+ WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);\r
+}\r
+\r