]> git.proxmox.com Git - mirror_edk2.git/commitdiff
1. Save/restore ICR high 32bit value and check Delivery Status before sending IPI...
authorJeff Fan <jeff.fan@intel.com>
Fri, 11 Jul 2014 02:36:56 +0000 (02:36 +0000)
committervanjeff <vanjeff@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 11 Jul 2014 02:36:56 +0000 (02:36 +0000)
2. Save/restore CPU Interrupt state around sending IPI. It could avoid sending IPI be interrupted by CPU interrupt handler.
3. Add note for SetApicMode() API that must not be called from an interrupt handler or SMI handler.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
Reviewed-by: Kinney, Michael <michael.d.kinney@intel.com>
Reviewed-by: Mudusuru, Giri <giri.p.mudusuru@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15652 6f19259b-4bc3-4df7-8a09-765794883524

UefiCpuPkg/Include/Library/LocalApicLib.h
UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c

index 896020487650dd3b440e993152b89b964b95ddc3..b92b99e11519638a7feb77eccfd57a5740ad24d6 100644 (file)
@@ -4,7 +4,7 @@
   Local APIC library assumes local APIC is enabled. It does not\r
   handles cases where local APIC is disabled.\r
 \r
-  Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2010 - 2014, 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
@@ -68,6 +68,9 @@ GetApicMode (
   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
+  @note  This API must not be called from an interrupt handler or SMI handler.\r
+         It may result in unpredictable behavior.\r
 **/\r
 VOID\r
 EFIAPI\r
index 6bf9c43dc945cb2edc76206b6d8ded01fac435ca..6f8cd2eb9b48c444cac6a2b21134da611f86dd89 100644 (file)
@@ -139,18 +139,47 @@ SendIpi (
   )\r
 {\r
   LOCAL_APIC_ICR_LOW IcrLowReg;\r
+  UINT32             IcrHigh;\r
+  BOOLEAN            InterruptState;\r
 \r
   ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);\r
   ASSERT (ApicId <= 0xff);\r
 \r
+  InterruptState = SaveAndDisableInterrupts ();\r
+\r
+  //\r
+  // Save existing contents of ICR high 32 bits\r
+  //\r
+  IcrHigh = ReadLocalApicReg (XAPIC_ICR_HIGH_OFFSET);\r
+\r
+  //\r
+  // Wait for DeliveryStatus clear in case a previous IPI\r
+  //  is still being sent\r
+  //\r
+  do {\r
+    IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);\r
+  } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
+\r
   //\r
   // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.\r
   //\r
   WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
   WriteLocalApicReg (XAPIC_ICR_LOW_OFFSET, IcrLow);\r
+\r
+  //\r
+  // Wait for DeliveryStatus clear again\r
+  //\r
   do {\r
     IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);\r
   } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
+\r
+  //\r
+  // And restore old contents of ICR high\r
+  //\r
+  WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, IcrHigh);\r
+\r
+  SetInterruptState (InterruptState);\r
+\r
 }\r
 \r
 //\r
@@ -193,6 +222,9 @@ GetApicMode (
   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
+  @note  This API must not be called from an interrupt handler or SMI handler.\r
+         It may result in unpredictable behavior.\r
 **/\r
 VOID\r
 EFIAPI\r
index ec54d01eb6653e6aaf769e6085334bad263b0a7b..bf318e06e4b73baa1bb8e7c1610aa9966a83f859 100644 (file)
@@ -180,19 +180,55 @@ SendIpi (
   UINT64             MsrValue;\r
   LOCAL_APIC_ICR_LOW IcrLowReg;\r
   UINTN              LocalApciBaseAddress;\r
+  UINT32             IcrHigh;\r
+  BOOLEAN            InterruptState;\r
 \r
+  //\r
+  // Legacy APIC or X2APIC?\r
+  //\r
   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {\r
     ASSERT (ApicId <= 0xff);\r
 \r
+    InterruptState = SaveAndDisableInterrupts ();\r
+\r
     //\r
-    // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.\r
+    // Get base address of this LAPIC\r
     //\r
     LocalApciBaseAddress = GetLocalApicBaseAddress();\r
+\r
+    //\r
+    // Save existing contents of ICR high 32 bits\r
+    //\r
+    IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);\r
+\r
+    //\r
+    // Wait for DeliveryStatus clear in case a previous IPI\r
+    //  is still being sent\r
+    //\r
+    do {\r
+      IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);\r
+    } while (IcrLowReg.Bits.DeliveryStatus != 0);\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 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);\r
     MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);\r
+\r
+    //\r
+    // Wait for DeliveryStatus clear again\r
+    //\r
     do {\r
       IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);\r
     } while (IcrLowReg.Bits.DeliveryStatus != 0);\r
+\r
+    //\r
+    // And restore old contents of ICR high\r
+    //\r
+    MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);\r
+\r
+    SetInterruptState (InterruptState);\r
+\r
   } else {\r
     //\r
     // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an \r
@@ -242,6 +278,9 @@ GetApicMode (
   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
+  @note  This API must not be called from an interrupt handler or SMI handler.\r
+         It may result in unpredictable behavior.\r
 **/\r
 VOID\r
 EFIAPI\r