VOID\r
);\r
\r
+/**\r
+ Get the value of the local APIC version register.\r
+\r
+ @return the value of the local APIC version register.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetApicVersion (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Send a Fixed 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 The local APIC ID of the target processor.\r
+ @param Vector The vector number of the interrupt being sent.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendFixedIpi (\r
+ IN UINT32 ApicId,\r
+ IN UINT8 Vector\r
+ );\r
+\r
+/**\r
+ Send a Fixed IPI to all processors excluding self.\r
+\r
+ This function returns after the IPI has been accepted by the target processors. \r
+\r
+ @param Vector The vector number of the interrupt being sent.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendFixedIpiAllExcludingSelf (\r
+ IN UINT8 Vector\r
+ );\r
+\r
/**\r
Send a SMI IPI to a specified target processor.\r
\r
VOID\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
/**\r
Read the initial count value from the init-count register.\r
\r
IN UINT8 Vector\r
);\r
\r
+/**\r
+ Get the state of the local APIC timer.\r
+\r
+ @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
+ @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
+ @param Vector Return the timer interrupt vector number.\r
+**/\r
+VOID\r
+EFIAPI\r
+GetApicTimerState (\r
+ OUT UINTN *DivideValue OPTIONAL,\r
+ OUT BOOLEAN *PeriodicMode OPTIONAL,\r
+ OUT UINT8 *Vector OPTIONAL\r
+ );\r
+\r
/**\r
Enable the local APIC timer interrupt.\r
**/\r
//\r
// Definition for Local APIC registers and related values\r
//\r
-#define XAPIC_ID_OFFSET 0x0\r
+#define XAPIC_ID_OFFSET 0x20\r
+#define XAPIC_VERSION_OFFSET 0x30\r
#define XAPIC_EOI_OFFSET 0x0b0\r
#define XAPIC_ICR_DFR_OFFSET 0x0e0\r
#define XAPIC_SPURIOUS_VECTOR_OFFSET 0x0f0\r
#define XAPIC_ICR_LOW_OFFSET 0x300\r
#define XAPIC_ICR_HIGH_OFFSET 0x310\r
#define XAPIC_LVT_TIMER_OFFSET 0x320\r
-#define XAPIC_LINT0_VECTOR_OFFSET 0x350\r
-#define XAPIC_LINT1_VECTOR_OFFSET 0x360\r
+#define XAPIC_LVT_LINT0_OFFSET 0x350\r
+#define XAPIC_LVT_LINT1_OFFSET 0x360\r
#define XAPIC_TIMER_INIT_COUNT_OFFSET 0x380\r
#define XAPIC_TIMER_CURRENT_COUNT_OFFSET 0x390\r
#define XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET 0x3E0\r
UINT64 Uint64;\r
} MSR_IA32_APIC_BASE;\r
\r
+//\r
+// Local APIC Version Register.\r
+//\r
+typedef union {\r
+ struct {\r
+ UINT32 Version:8; ///< The version numbers of the local APIC.\r
+ UINT32 Reserved0:8; ///< Reserved.\r
+ UINT32 MaxLvtEntry:8; ///< Number of LVT entries minus 1.\r
+ UINT32 EoiBroadcastSuppression:1; ///< 1 if EOI-broadcast suppression supported.\r
+ UINT32 Reserved1:7; ///< Reserved.\r
+ } Bits;\r
+ UINT32 Uint32;\r
+} LOCAL_APIC_VERSION;\r
+\r
//\r
// Low half of Interrupt Command Register (ICR).\r
//\r
return ApicId;\r
}\r
\r
+/**\r
+ Get the value of the local APIC version register.\r
+\r
+ @return the value of the local APIC version register.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetApicVersion (\r
+ VOID\r
+ )\r
+{\r
+ return ReadLocalApicReg (XAPIC_VERSION_OFFSET);\r
+}\r
+\r
+/**\r
+ Send a Fixed 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 The local APIC ID of the target processor.\r
+ @param Vector The vector number of the interrupt being sent.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendFixedIpi (\r
+ IN UINT32 ApicId,\r
+ IN UINT8 Vector\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
+ IcrLow.Bits.Level = 1;\r
+ IcrLow.Bits.Vector = Vector;\r
+ SendIpi (IcrLow.Uint32, ApicId);\r
+}\r
+\r
+/**\r
+ Send a Fixed IPI to all processors excluding self.\r
+\r
+ This function returns after the IPI has been accepted by the target processors. \r
+\r
+ @param Vector The vector number of the interrupt being sent.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendFixedIpiAllExcludingSelf (\r
+ IN UINT8 Vector\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
+ IcrLow.Bits.Level = 1;\r
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
+ IcrLow.Bits.Vector = Vector;\r
+ SendIpi (IcrLow.Uint32, 0);\r
+}\r
+\r
/**\r
Send a SMI IPI to a specified target processor.\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.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_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
+ WriteLocalApicReg (XAPIC_LVT_LINT0_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.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_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
+ WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);\r
}\r
\r
/**\r
WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
}\r
\r
+/**\r
+ Get the state of the local APIC timer.\r
+\r
+ @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
+ @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
+ @param Vector Return the timer interrupt vector number.\r
+**/\r
+VOID\r
+EFIAPI\r
+GetApicTimerState (\r
+ OUT UINTN *DivideValue OPTIONAL,\r
+ OUT BOOLEAN *PeriodicMode OPTIONAL,\r
+ OUT UINT8 *Vector OPTIONAL\r
+ )\r
+{\r
+ UINT32 Divisor;\r
+ LOCAL_APIC_DCR Dcr;\r
+ LOCAL_APIC_LVT_TIMER LvtTimer;\r
+\r
+ if (DivideValue != NULL) {\r
+ Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
+ Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
+ Divisor = (Divisor + 1) & 0x7;\r
+ *DivideValue = ((UINTN)1) << Divisor;\r
+ }\r
+\r
+ if (PeriodicMode != NULL || Vector != NULL) {\r
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
+ if (PeriodicMode != NULL) {\r
+ if (LvtTimer.Bits.TimerMode == 1) {\r
+ *PeriodicMode = TRUE;\r
+ } else {\r
+ *PeriodicMode = FALSE;\r
+ }\r
+ }\r
+ if (Vector != NULL) {\r
+ *Vector = (UINT8) LvtTimer.Bits.Vector;\r
+ }\r
+ }\r
+}\r
+\r
/**\r
Enable the local APIC timer interrupt.\r
**/\r
return ApicId;\r
}\r
\r
+/**\r
+ Get the value of the local APIC version register.\r
+\r
+ @return the value of the local APIC version register.\r
+**/\r
+UINT32\r
+EFIAPI\r
+GetApicVersion (\r
+ VOID\r
+ )\r
+{\r
+ return ReadLocalApicReg (XAPIC_VERSION_OFFSET);\r
+}\r
+\r
+/**\r
+ Send a Fixed 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 The local APIC ID of the target processor.\r
+ @param Vector The vector number of the interrupt being sent.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendFixedIpi (\r
+ IN UINT32 ApicId,\r
+ IN UINT8 Vector\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
+ IcrLow.Bits.Level = 1;\r
+ IcrLow.Bits.Vector = Vector;\r
+ SendIpi (IcrLow.Uint32, ApicId);\r
+}\r
+\r
+/**\r
+ Send a Fixed IPI to all processors excluding self.\r
+\r
+ This function returns after the IPI has been accepted by the target processors. \r
+\r
+ @param Vector The vector number of the interrupt being sent.\r
+**/\r
+VOID\r
+EFIAPI\r
+SendFixedIpiAllExcludingSelf (\r
+ IN UINT8 Vector\r
+ )\r
+{\r
+ LOCAL_APIC_ICR_LOW IcrLow;\r
+\r
+ IcrLow.Uint32 = 0;\r
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;\r
+ IcrLow.Bits.Level = 1;\r
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;\r
+ IcrLow.Bits.Vector = Vector;\r
+ SendIpi (IcrLow.Uint32, 0);\r
+}\r
+\r
/**\r
Send a SMI IPI to a specified target processor.\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.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_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
+ WriteLocalApicReg (XAPIC_LVT_LINT0_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.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_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
+ WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);\r
}\r
\r
/**\r
WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);\r
}\r
\r
+/**\r
+ Get the state of the local APIC timer.\r
+\r
+ @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.\r
+ @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.\r
+ @param Vector Return the timer interrupt vector number.\r
+**/\r
+VOID\r
+EFIAPI\r
+GetApicTimerState (\r
+ OUT UINTN *DivideValue OPTIONAL,\r
+ OUT BOOLEAN *PeriodicMode OPTIONAL,\r
+ OUT UINT8 *Vector OPTIONAL\r
+ )\r
+{\r
+ UINT32 Divisor;\r
+ LOCAL_APIC_DCR Dcr;\r
+ LOCAL_APIC_LVT_TIMER LvtTimer;\r
+\r
+ if (DivideValue != NULL) {\r
+ Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);\r
+ Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);\r
+ Divisor = (Divisor + 1) & 0x7;\r
+ *DivideValue = ((UINTN)1) << Divisor;\r
+ }\r
+\r
+ if (PeriodicMode != NULL || Vector != NULL) {\r
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);\r
+ if (PeriodicMode != NULL) {\r
+ if (LvtTimer.Bits.TimerMode == 1) {\r
+ *PeriodicMode = TRUE;\r
+ } else {\r
+ *PeriodicMode = FALSE;\r
+ }\r
+ }\r
+ if (Vector != NULL) {\r
+ *Vector = (UINT8) LvtTimer.Bits.Vector;\r
+ }\r
+ }\r
+}\r
+\r
/**\r
Enable the local APIC timer interrupt.\r
**/\r