From: rsun3 Date: Thu, 26 Aug 2010 05:58:42 +0000 (+0000) Subject: Improve Local APIC library class. Add new library APIs: GetApicVersion(), SendFixedIp... X-Git-Tag: edk2-stable201903~15578 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=ae40aef1fb4f5f34e5273b6fd5d4103bf6c7dd2d Improve Local APIC library class. Add new library APIs: GetApicVersion(), SendFixedIpi(), SendFixedIpiAllExcludingSelf(), GetApicTimerState(). Remove GetApicTimerDivisor (), its functionality can be covered by GetApicTimerState(). git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10824 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/UefiCpuPkg/Include/Library/LocalApicLib.h b/UefiCpuPkg/Include/Library/LocalApicLib.h index 58e3474e88..d565dad96c 100644 --- a/UefiCpuPkg/Include/Library/LocalApicLib.h +++ b/UefiCpuPkg/Include/Library/LocalApicLib.h @@ -75,6 +75,45 @@ GetApicId ( VOID ); +/** + Get the value of the local APIC version register. + + @return the value of the local APIC version register. +**/ +UINT32 +EFIAPI +GetApicVersion ( + VOID + ); + +/** + Send a Fixed IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId The local APIC ID of the target processor. + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpi ( + IN UINT32 ApicId, + IN UINT8 Vector + ); + +/** + Send a Fixed IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpiAllExcludingSelf ( + IN UINT8 Vector + ); + /** Send a SMI IPI to a specified target processor. @@ -173,18 +212,6 @@ ProgramVirtualWireMode ( VOID ); -/** - Get the divide value from the DCR (Divide Configuration Register) by which - the processor's bus clock is divided to form the time base for the APIC timer. - - @return The divide value is one of 1,2,4,8,16,32,64,128. -**/ -UINTN -EFIAPI -GetApicTimerDivisor ( - VOID - ); - /** Read the initial count value from the init-count register. @@ -227,6 +254,21 @@ InitializeApicTimer ( IN UINT8 Vector ); +/** + Get the state of the local APIC timer. + + @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector Return the timer interrupt vector number. +**/ +VOID +EFIAPI +GetApicTimerState ( + OUT UINTN *DivideValue OPTIONAL, + OUT BOOLEAN *PeriodicMode OPTIONAL, + OUT UINT8 *Vector OPTIONAL + ); + /** Enable the local APIC timer interrupt. **/ diff --git a/UefiCpuPkg/Include/Register/LocalApic.h b/UefiCpuPkg/Include/Register/LocalApic.h index 7535ef50e9..e22900d0cc 100644 --- a/UefiCpuPkg/Include/Register/LocalApic.h +++ b/UefiCpuPkg/Include/Register/LocalApic.h @@ -30,15 +30,16 @@ // // Definition for Local APIC registers and related values // -#define XAPIC_ID_OFFSET 0x0 +#define XAPIC_ID_OFFSET 0x20 +#define XAPIC_VERSION_OFFSET 0x30 #define XAPIC_EOI_OFFSET 0x0b0 #define XAPIC_ICR_DFR_OFFSET 0x0e0 #define XAPIC_SPURIOUS_VECTOR_OFFSET 0x0f0 #define XAPIC_ICR_LOW_OFFSET 0x300 #define XAPIC_ICR_HIGH_OFFSET 0x310 #define XAPIC_LVT_TIMER_OFFSET 0x320 -#define XAPIC_LINT0_VECTOR_OFFSET 0x350 -#define XAPIC_LINT1_VECTOR_OFFSET 0x360 +#define XAPIC_LVT_LINT0_OFFSET 0x350 +#define XAPIC_LVT_LINT1_OFFSET 0x360 #define XAPIC_TIMER_INIT_COUNT_OFFSET 0x380 #define XAPIC_TIMER_CURRENT_COUNT_OFFSET 0x390 #define XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET 0x3E0 @@ -71,6 +72,20 @@ typedef union { UINT64 Uint64; } MSR_IA32_APIC_BASE; +// +// Local APIC Version Register. +// +typedef union { + struct { + UINT32 Version:8; ///< The version numbers of the local APIC. + UINT32 Reserved0:8; ///< Reserved. + UINT32 MaxLvtEntry:8; ///< Number of LVT entries minus 1. + UINT32 EoiBroadcastSuppression:1; ///< 1 if EOI-broadcast suppression supported. + UINT32 Reserved1:7; ///< Reserved. + } Bits; + UINT32 Uint32; +} LOCAL_APIC_VERSION; + // // Low half of Interrupt Command Register (ICR). // diff --git a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c index 16dbd4be6e..1ac3853071 100644 --- a/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c +++ b/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c @@ -202,6 +202,67 @@ GetApicId ( return ApicId; } +/** + Get the value of the local APIC version register. + + @return the value of the local APIC version register. +**/ +UINT32 +EFIAPI +GetApicVersion ( + VOID + ) +{ + return ReadLocalApicReg (XAPIC_VERSION_OFFSET); +} + +/** + Send a Fixed IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId The local APIC ID of the target processor. + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpi ( + IN UINT32 ApicId, + IN UINT8 Vector + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED; + IcrLow.Bits.Level = 1; + IcrLow.Bits.Vector = Vector; + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send a Fixed IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpiAllExcludingSelf ( + IN UINT8 Vector + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + IcrLow.Bits.Vector = Vector; + SendIpi (IcrLow.Uint32, 0); +} + /** Send a SMI IPI to a specified target processor. @@ -381,43 +442,22 @@ ProgramVirtualWireMode ( // // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high. // - Lint.Uint32 = ReadLocalApicReg (XAPIC_LINT0_VECTOR_OFFSET); + Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET); Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT; Lint.Bits.InputPinPolarity = 0; Lint.Bits.TriggerMode = 0; Lint.Bits.Mask = 0; - WriteLocalApicReg (XAPIC_LINT0_VECTOR_OFFSET, Lint.Uint32); + WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32); // // Program the LINT0 vector entry as NMI. Not masked, edge, active high. // - Lint.Uint32 = ReadLocalApicReg (XAPIC_LINT1_VECTOR_OFFSET); + Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET); Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI; Lint.Bits.InputPinPolarity = 0; Lint.Bits.TriggerMode = 0; Lint.Bits.Mask = 0; - WriteLocalApicReg (XAPIC_LINT1_VECTOR_OFFSET, Lint.Uint32); -} - -/** - Get the divide value from the DCR (Divide Configuration Register) by which - the processor's bus clock is divided to form the time base for the APIC timer. - - @return The divide value is one of 1,2,4,8,16,32,64,128. -**/ -UINTN -EFIAPI -GetApicTimerDivisor ( - VOID - ) -{ - UINT32 DivideValue; - LOCAL_APIC_DCR Dcr; - - Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET); - DivideValue = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2); - DivideValue = (DivideValue + 1) & 0x7; - return ((UINTN)1) << DivideValue; + WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32); } /** @@ -510,6 +550,47 @@ InitializeApicTimer ( WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32); } +/** + Get the state of the local APIC timer. + + @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector Return the timer interrupt vector number. +**/ +VOID +EFIAPI +GetApicTimerState ( + OUT UINTN *DivideValue OPTIONAL, + OUT BOOLEAN *PeriodicMode OPTIONAL, + OUT UINT8 *Vector OPTIONAL + ) +{ + UINT32 Divisor; + LOCAL_APIC_DCR Dcr; + LOCAL_APIC_LVT_TIMER LvtTimer; + + if (DivideValue != NULL) { + Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET); + Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2); + Divisor = (Divisor + 1) & 0x7; + *DivideValue = ((UINTN)1) << Divisor; + } + + if (PeriodicMode != NULL || Vector != NULL) { + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + if (PeriodicMode != NULL) { + if (LvtTimer.Bits.TimerMode == 1) { + *PeriodicMode = TRUE; + } else { + *PeriodicMode = FALSE; + } + } + if (Vector != NULL) { + *Vector = (UINT8) LvtTimer.Bits.Vector; + } + } +} + /** Enable the local APIC timer interrupt. **/ diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c index bff66eeb1b..7ee13c3ba6 100644 --- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c +++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c @@ -285,6 +285,67 @@ GetApicId ( return ApicId; } +/** + Get the value of the local APIC version register. + + @return the value of the local APIC version register. +**/ +UINT32 +EFIAPI +GetApicVersion ( + VOID + ) +{ + return ReadLocalApicReg (XAPIC_VERSION_OFFSET); +} + +/** + Send a Fixed IPI to a specified target processor. + + This function returns after the IPI has been accepted by the target processor. + + @param ApicId The local APIC ID of the target processor. + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpi ( + IN UINT32 ApicId, + IN UINT8 Vector + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED; + IcrLow.Bits.Level = 1; + IcrLow.Bits.Vector = Vector; + SendIpi (IcrLow.Uint32, ApicId); +} + +/** + Send a Fixed IPI to all processors excluding self. + + This function returns after the IPI has been accepted by the target processors. + + @param Vector The vector number of the interrupt being sent. +**/ +VOID +EFIAPI +SendFixedIpiAllExcludingSelf ( + IN UINT8 Vector + ) +{ + LOCAL_APIC_ICR_LOW IcrLow; + + IcrLow.Uint32 = 0; + IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED; + IcrLow.Bits.Level = 1; + IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF; + IcrLow.Bits.Vector = Vector; + SendIpi (IcrLow.Uint32, 0); +} + /** Send a SMI IPI to a specified target processor. @@ -464,43 +525,22 @@ ProgramVirtualWireMode ( // // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high. // - Lint.Uint32 = ReadLocalApicReg (XAPIC_LINT0_VECTOR_OFFSET); + Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET); Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT; Lint.Bits.InputPinPolarity = 0; Lint.Bits.TriggerMode = 0; Lint.Bits.Mask = 0; - WriteLocalApicReg (XAPIC_LINT0_VECTOR_OFFSET, Lint.Uint32); + WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32); // // Program the LINT0 vector entry as NMI. Not masked, edge, active high. // - Lint.Uint32 = ReadLocalApicReg (XAPIC_LINT1_VECTOR_OFFSET); + Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET); Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI; Lint.Bits.InputPinPolarity = 0; Lint.Bits.TriggerMode = 0; Lint.Bits.Mask = 0; - WriteLocalApicReg (XAPIC_LINT1_VECTOR_OFFSET, Lint.Uint32); -} - -/** - Get the divide value from the DCR (Divide Configuration Register) by which - the processor's bus clock is divided to form the time base for the APIC timer. - - @return The divide value is one of 1,2,4,8,16,32,64,128. -**/ -UINTN -EFIAPI -GetApicTimerDivisor ( - VOID - ) -{ - UINT32 DivideValue; - LOCAL_APIC_DCR Dcr; - - Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET); - DivideValue = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2); - DivideValue = (DivideValue + 1) & 0x7; - return ((UINTN)1) << DivideValue; + WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32); } /** @@ -593,6 +633,47 @@ InitializeApicTimer ( WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32); } +/** + Get the state of the local APIC timer. + + @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128. + @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot. + @param Vector Return the timer interrupt vector number. +**/ +VOID +EFIAPI +GetApicTimerState ( + OUT UINTN *DivideValue OPTIONAL, + OUT BOOLEAN *PeriodicMode OPTIONAL, + OUT UINT8 *Vector OPTIONAL + ) +{ + UINT32 Divisor; + LOCAL_APIC_DCR Dcr; + LOCAL_APIC_LVT_TIMER LvtTimer; + + if (DivideValue != NULL) { + Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET); + Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2); + Divisor = (Divisor + 1) & 0x7; + *DivideValue = ((UINTN)1) << Divisor; + } + + if (PeriodicMode != NULL || Vector != NULL) { + LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET); + if (PeriodicMode != NULL) { + if (LvtTimer.Bits.TimerMode == 1) { + *PeriodicMode = TRUE; + } else { + *PeriodicMode = FALSE; + } + } + if (Vector != NULL) { + *Vector = (UINT8) LvtTimer.Bits.Vector; + } + } +} + /** Enable the local APIC timer interrupt. **/