summaryrefslogtreecommitdiffstats
path: root/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c')
-rw-r--r--UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
index ec54d01eb6..bf318e06e4 100644
--- a/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
+++ b/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -180,19 +180,55 @@ SendIpi (
UINT64 MsrValue;
LOCAL_APIC_ICR_LOW IcrLowReg;
UINTN LocalApciBaseAddress;
+ UINT32 IcrHigh;
+ BOOLEAN InterruptState;
+ //
+ // Legacy APIC or X2APIC?
+ //
if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
ASSERT (ApicId <= 0xff);
+ InterruptState = SaveAndDisableInterrupts ();
+
//
- // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
+ // Get base address of this LAPIC
//
LocalApciBaseAddress = GetLocalApicBaseAddress();
+
+ //
+ // Save existing contents of ICR high 32 bits
+ //
+ IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);
+
+ //
+ // Wait for DeliveryStatus clear in case a previous IPI
+ // is still being sent
+ //
+ do {
+ IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
+ } while (IcrLowReg.Bits.DeliveryStatus != 0);
+
+ //
+ // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
+ //
MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);
+
+ //
+ // Wait for DeliveryStatus clear again
+ //
do {
IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
} while (IcrLowReg.Bits.DeliveryStatus != 0);
+
+ //
+ // And restore old contents of ICR high
+ //
+ MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);
+
+ SetInterruptState (InterruptState);
+
} else {
//
// For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
@@ -242,6 +278,9 @@ GetApicMode (
If the specified local APIC mode can't be set as current, then ASSERT.
@param ApicMode APIC mode to be set.
+
+ @note This API must not be called from an interrupt handler or SMI handler.
+ It may result in unpredictable behavior.
**/
VOID
EFIAPI