/**
  Stalls the CPU for at least the given number of ticks.

  Stalls the CPU for at least the given number of ticks. It's invoked by
  MicroSecondDelay() and NanoSecondDelay().

  @param  Delay     A period of time to delay in ticks.

**/
STATIC
VOID
InternalAcpiDelay (
  IN      UINT32                    Delay
  )
{
  UINT32                            Ticks;
  UINT32                            Times;

  Times    = Delay >> 22;
  Delay   &= BIT22 - 1;
  do {
    //
    // The target timer count is calculated here
    //
    Ticks    = InternalAcpiGetTimerTick () + Delay;
    Delay    = BIT22;
    //
    // Wait until time out
    // Delay >= 2^23 could not be handled by this function
    // Timer wrap-arounds are handled correctly by this function
    //
    while (((Ticks - InternalAcpiGetTimerTick ()) & BIT23) == 0) {
      CpuPause ();
    }
  } while (Times-- > 0);
}
Beispiel #2
0
EFIAPI
AcquireSpinLock (
  IN OUT  SPIN_LOCK                 *SpinLock
  )
{
  UINT64                            Tick;
  UINT64                            Start, End;
  UINT64                            Timeout;

  Tick = 0;
  Start = 0;
  End = 0;
  if (PcdGet32 (PcdSpinLockTimeout) > 0) {
    Tick = GetPerformanceCounter ();
    Timeout = DivU64x32 (
                MultU64x32 (
                  GetPerformanceCounterProperties (&Start, &End),
                  PcdGet32 (PcdSpinLockTimeout)
                  ),
                1000000
                );
    if (Start < End) {
      Tick += Timeout;
    } else {
      Tick -= Timeout;
    }
  }

  while (!AcquireSpinLockOrFail (SpinLock)) {
    CpuPause ();
    ASSERT ((Start < End) ^ (Tick <= GetPerformanceCounter ()));
  }
  return SpinLock;
}
Beispiel #3
0
/**
  Stalls the CPU for at least the given number of ticks.

  Stalls the CPU for at least the given number of ticks. It's invoked by
  MicroSecondDelay() and NanoSecondDelay().

  @param  Delay     A period of time to delay in ticks.

**/
STATIC
VOID
InternalAcpiDelay (
  IN      UINT32                    Delay
  )
{
  UINT32                            Ticks;
  UINT32                            Times;

  Times    = Delay >> (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2);
  Delay   &= (1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2)) - 1;
  do {
    //
    // The target timer count is calculated here
    //
    Ticks    = InternalAcpiGetTimerTick () + Delay;
    Delay    = 1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2);
    //
    // Wait until time out
    // Delay >= 2^23 (if ACPI provide 24-bit timer) or Delay >= 2^31 (if ACPI
    // provide 32-bit timer) could not be handled by this function
    // Timer wrap-arounds are handled correctly by this function
    //
    while (((Ticks - InternalAcpiGetTimerTick ()) & (1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 1))) == 0) {
      CpuPause ();
    }
  } while (Times-- > 0);
}
Beispiel #4
0
/**
  Stalls the CPU for at least the given number of ticks.

  Stalls the CPU for at least the given number of ticks. It's invoked by
  MicroSecondDelay() and NanoSecondDelay().

  @param  ApicBase  The base address of memory mapped registers of local APIC.
  @param  Delay     A period of time to delay in ticks.

**/
VOID
EFIAPI
InternalX86Delay (
  IN      UINTN                     ApicBase,
  IN      UINT32                    Delay
  )
{
  INT32                             Ticks;
  UINT32                            PowerOfTwoCounter;

  //
  // The target timer count is calculated here
  //
  Ticks = InternalX86GetTimerTick (ApicBase) - Delay;

  //
  // Wait until time out
  // Delay > 2^31 could not be handled by this function
  // Timer wrap-arounds are handled correctly by this function
  //
  PowerOfTwoCounter = GetPowerOfTwo32 (MmioRead32 (ApicBase + APIC_TMICT));
  while (((UINT32)(InternalX86GetTimerTick (ApicBase) - Ticks) & PowerOfTwoCounter) == 0) {
    CpuPause ();
  }
}
Beispiel #5
0
/**
  The function is invoked after SMBASE relocation in S3 path to restores CPU status.

  The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
  data saved by normal boot path for both BSP and APs.

**/
VOID
InitializeCpu (
  VOID
  )
{
  CPU_REGISTER_TABLE         *RegisterTableList;
  UINT32                     InitApicId;
  UINTN                      Index;

  RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
  InitApicId = GetInitialApicId ();
  for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
    if (RegisterTableList[Index].InitialApicId == InitApicId) {
      SetProcessorRegister (&RegisterTableList[Index]);
      break;
    }
  }

  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
  //
  // StackStart was updated when APs were waken up in EarlyInitializeCpu.
  // Re-initialize StackAddress to original beginning address.
  //
  mExchangeInfo->StackStart  = (VOID *) (UINTN) mAcpiCpuData.StackAddress;
  mExchangeInfo->ApFunction  = (VOID *) (UINTN) MPRendezvousProcedure;

  //
  // Send INIT IPI - SIPI to all APs
  //
  SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);

  while (mNumberToFinish > 0) {
    CpuPause ();
  }
}
/**
  The function is invoked before SMBASE relocation in S3 path to restores CPU status.

  The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
  and restores MTRRs for both BSP and APs.

**/
VOID
InitializeCpuBeforeRebase (
  VOID
  )
{
  LoadMtrrData (mAcpiCpuData.MtrrTable);

  SetProcessorRegister ((CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable, mAcpiCpuData.NumberOfCpus);

  ProgramVirtualWireMode ();

  PrepareApStartupVector (mAcpiCpuData.StartupVector);

  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
  mExchangeInfo->ApFunction  = (VOID *) (UINTN) InitializeAp;

  //
  // Execute code for before SmmBaseReloc. Note: This flag is maintained across S3 boots.
  //
  mInitApsAfterSmmBaseReloc = FALSE;

  //
  // Send INIT IPI - SIPI to all APs
  //
  SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);

  while (mNumberToFinish > 0) {
    CpuPause ();
  }
}
/**
  Enable/Disable the interrupt of debug timer and return the interrupt state
  prior to the operation.

  If EnableStatus is TRUE, enable the interrupt of debug timer.
  If EnableStatus is FALSE, disable the interrupt of debug timer.

  @param[in] EnableStatus    Enable/Disable.

  @retval TRUE  Debug timer interrupt were enabled on entry to this call.
  @retval FALSE Debug timer interrupt were disabled on entry to this call.

**/
BOOLEAN
EFIAPI
SaveAndSetDebugTimerInterrupt (
  IN BOOLEAN                EnableStatus
  )
{
  BOOLEAN     OldDebugTimerInterruptState;

  OldDebugTimerInterruptState = GetApicTimerInterruptState ();

  if (OldDebugTimerInterruptState != EnableStatus) {
    if (EnableStatus) {
      EnableApicTimerInterrupt ();
    } else {
      DisableApicTimerInterrupt ();
    }
    //
    // Validate the Debug Timer interrupt state
    // This will make additional delay after Local Apic Timer interrupt state is changed.
    // Thus, CPU could handle the potential pending interrupt of Local Apic timer.
    //
    while (GetApicTimerInterruptState () != EnableStatus) {
      CpuPause ();
    }
  }

  return OldDebugTimerInterruptState;
}
Beispiel #8
0
/**
  The function is invoked after SMBASE relocation in S3 path to restors CPU status.

  The function is invoked after SMBASE relocation in S3 path. It restores configuration according to 
  data saved by normal boot path for both BSP and APs.

**/
VOID
InitializeCpu (
  VOID
  )
{
  CPU_REGISTER_TABLE         *RegisterTableList;
  UINT32                     InitApicId;
  UINTN                      Index;

  RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
  InitApicId = GetInitialApicId ();
  for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
    if (RegisterTableList[Index].InitialApicId == InitApicId) {
      SetProcessorRegister (&RegisterTableList[Index]);
      break;
    }
  } 

  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
  mExchangeInfo->ApFunction  = (VOID *) (UINTN) MPRendezvousProcedure;

  //
  // Send INIT IPI - SIPI to all APs
  //
  SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);

  while (mNumberToFinish > 0) {
    CpuPause ();
  }
}
/**
  Stalls the CPU for at least the given number of ticks.

  Stalls the CPU for at least the given number of ticks. It's invoked by
  MicroSecondDelay() and NanoSecondDelay().

  @param  Delay     A period of time to delay in ticks.

**/
VOID
EFIAPI
InternalX86Delay (
  IN      UINT32                    Delay
  )
{
  INT32                             Ticks;
  UINT32                            Times;
  UINT32                            InitCount;
  UINT32                            StartTick;

  //
  // In case Delay is too larger, separate it into several small delay slot.
  // Devided Delay by half value of Init Count is to avoid Delay close to
  // the Init Count, timeout maybe missing if the time consuming between 2
  // GetApicTimerCurrentCount() invoking is larger than the time gap between
  // Delay and the Init Count.
  //
  InitCount = GetApicTimerInitCount ();
  Times     = Delay / (InitCount / 2);
  Delay     = Delay % (InitCount / 2);

  //
  // Get Start Tick and do delay
  //
  StartTick  = GetApicTimerCurrentCount ();
  do {
    //
    // Wait until time out by Delay value
    //
    do {
      CpuPause ();
      //
      // Get Ticks from Start to Current.
      //
      Ticks = StartTick - GetApicTimerCurrentCount ();
      //
      // Ticks < 0 means Timer wrap-arounds happens.
      //
      if (Ticks < 0) {
        Ticks += InitCount;
      }
    } while ((UINT32)Ticks < Delay);

    //
    // Update StartTick and Delay for next delay slot
    //
    StartTick -= (StartTick > Delay) ?  Delay : (Delay - InitCount);
    Delay      = InitCount / 2;
  } while (Times-- > 0);
}
/**
  Stalls the CPU for at least the given number of ticks.

  Stalls the CPU for at least the given number of ticks. It's invoked by
  MicroSecondDelay() and NanoSecondDelay().

  @param  Delay     A period of time to delay in ticks.

**/
VOID
EFIAPI
InternalX86Delay (
  IN      UINT32                    Delay
  )
{
  INT32                             Ticks;
  UINT32                            Times;
  UINT32                            InitCount;
  UINT32                            StartTick;
  BOOLEAN                           IsOverTurn;

  //
  // The target timer count is calculated here
  //
  InitCount = GetApicTimerInitCount ();
  Times     = Delay / InitCount;
  Delay     = Delay % InitCount;

  do {
    //
    // Get Start Tick
    //
    IsOverTurn = FALSE;
    StartTick  = GetApicTimerCurrentCount ();

    //
    // Wait until time out
    //
    do {
      CpuPause ();
      //
      // Get Ticks from Start to Current.
      //
      Ticks = StartTick - GetApicTimerCurrentCount ();
      //
      // Ticks < 0 means OverTurn happens.
      //
      if (Ticks < 0 || IsOverTurn) {
        Ticks += InitCount;
        IsOverTurn = TRUE;
      }
    } while ((UINT32) Ticks <= Delay);

    //
    // Wait next round Delay
    //
    Delay = InitCount;
  } while (Times-- > 0);
}
Beispiel #11
0
/**
  Acquire a spin lock when Multi-processor supported.

  It will block in the function if cannot get the access control.
  If Multi-processor is not supported, return directly.

  @param[in, out] MpSpinLock      A pointer to the spin lock.

**/
VOID
AcquireMpSpinLock (
  IN OUT SPIN_LOCK           *MpSpinLock
  )
{
  if (!MultiProcessorDebugSupport()) {
    return;
  }

  while (TRUE) {
    if (AcquireSpinLockOrFail (MpSpinLock)) {
      break;
    }
    CpuPause ();
    continue;
  }
}
/**
  The function is invoked after SMBASE relocation in S3 path to restores CPU status.

  The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
  data saved by normal boot path for both BSP and APs.

**/
VOID
InitializeCpuAfterRebase (
  VOID
  )
{
  SetProcessorRegister ((CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable, mAcpiCpuData.NumberOfCpus);

  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;

  //
  // Signal that SMM base relocation is complete and to continue initialization.
  //
  mInitApsAfterSmmBaseReloc = TRUE;

  while (mNumberToFinish > 0) {
    CpuPause ();
  }
}
Beispiel #13
0
/**
  Callback function for ExitBootServices.

  @param[in]  Event             Event whose notification function is being invoked.
  @param[in]  Context           The pointer to the notification function's context,
                                which is implementation-dependent.

**/
VOID
EFIAPI
MpInitChangeApLoopCallback (
  IN EFI_EVENT                Event,
  IN VOID                     *Context
  )
{
  CPU_MP_DATA               *CpuMpData;

  CpuMpData = GetCpuMpData ();
  CpuMpData->PmCodeSegment = GetProtectedModeCS ();
  CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
  mNumberToFinish = CpuMpData->CpuCount - 1;
  WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);
  while (mNumberToFinish > 0) {
    CpuPause ();
  }
  DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));
}
Beispiel #14
0
/**
  The function is invoked before SMBASE relocation in S3 path to restors CPU status.

  The function is invoked before SMBASE relocation in S3 path. It does first time microcode load 
  and restores MTRRs for both BSP and APs.

**/
VOID
EarlyInitializeCpu (
  VOID
  )
{
  CPU_REGISTER_TABLE         *RegisterTableList;
  UINT32                     InitApicId;
  UINTN                      Index;

  LoadMtrrData (mAcpiCpuData.MtrrTable);

  //
  // Find processor number for this CPU.
  //
  RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
  InitApicId = GetInitialApicId ();
  for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
    if (RegisterTableList[Index].InitialApicId == InitApicId) {
      SetProcessorRegister (&RegisterTableList[Index]);
      break;
    }
  } 

  ProgramVirtualWireMode ();

  PrepareAPStartupVector (mAcpiCpuData.StartupVector);

  mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
  mExchangeInfo->ApFunction  = (VOID *) (UINTN) EarlyMPRendezvousProcedure;

  //
  // Send INIT IPI - SIPI to all APs
  //
  SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);

  while (mNumberToFinish > 0) {
    CpuPause ();
  }
}
/**
  AP initialization before then after SMBASE relocation in the S3 boot path.
**/
VOID
InitializeAp (
  VOID
  )
{
  UINTN                      TopOfStack;
  UINT8                      Stack[128];

  LoadMtrrData (mAcpiCpuData.MtrrTable);

  SetProcessorRegister ((CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable, mAcpiCpuData.NumberOfCpus);

  //
  // Count down the number with lock mechanism.
  //
  InterlockedDecrement (&mNumberToFinish);

  //
  // Wait for BSP to signal SMM Base relocation done.
  //
  while (!mInitApsAfterSmmBaseReloc) {
    CpuPause ();
  }

  ProgramVirtualWireMode ();
  DisableLvtInterrupts ();

  SetProcessorRegister ((CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable, mAcpiCpuData.NumberOfCpus);

  //
  // Place AP into the safe code, count down the number with lock mechanism in the safe code.
  //
  TopOfStack  = (UINTN) Stack + sizeof (Stack);
  TopOfStack &= ~(UINTN) (CPU_STACK_ALIGNMENT - 1);
  CopyMem ((VOID *) (UINTN) mApHltLoopCode, mApHltLoopCodeTemplate, sizeof (mApHltLoopCodeTemplate));
  TransferApToSafeState ((UINTN)mApHltLoopCode, TopOfStack, (UINTN)&mNumberToFinish);
}
Beispiel #16
0
/**
  This function will be called from AP reset code if BSP uses WakeUpAP.

  @param ExchangeInfo     Pointer to the MP exchange info buffer
  @param NumApsExecuting  Number of current executing AP
**/
VOID
EFIAPI
ApCFunction (
  IN MP_CPU_EXCHANGE_INFO      *ExchangeInfo,
  IN UINTN                     NumApsExecuting
  )
{
  PEI_CPU_MP_DATA            *PeiCpuMpData;
  UINTN                      ProcessorNumber;
  EFI_AP_PROCEDURE           Procedure;
  UINTN                      BistData;
  volatile UINT32            *ApStartupSignalBuffer;

  PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
  while (TRUE) {
    if (PeiCpuMpData->InitFlag) {
      ProcessorNumber = NumApsExecuting;
      //
      // Sync BSP's Control registers to APs
      //
      RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE);
      //
      // This is first time AP wakeup, get BIST information from AP stack
      //
      BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));
      PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData;
      PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId ();
      if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) {
        //
        // Set x2APIC mode if there are any logical processor reporting
        // an APIC ID of 255 or greater.
        //
        AcquireSpinLock(&PeiCpuMpData->MpLock);
        PeiCpuMpData->X2ApicEnable = TRUE;
        ReleaseSpinLock(&PeiCpuMpData->MpLock);
      }
      //
      // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
      //
      MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
      MicrocodeDetect ();
      PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
    } else {
      //
      // Execute AP function if AP is not disabled
      //
      GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
      if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {
        //
        // Restore AP's volatile registers saved
        //
        RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
      }

      if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&
          (PeiCpuMpData->ApFunction != 0)) {
        PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;
        Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;
        //
        // Invoke AP function here
        //
        Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);
        //
        // Re-get the processor number due to BSP/AP maybe exchange in AP function
        //
        GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
        PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
      }
    }

    //
    // AP finished executing C code
    //
    InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);

    //
    // Place AP is specified loop mode
    //
    if (PeiCpuMpData->ApLoopMode == ApInHltLoop) {
      //
      // Save AP volatile registers
      //
      SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
      //
      // Place AP in Hlt-loop
      //
      while (TRUE) {
        DisableInterrupts ();
        CpuSleep ();
        CpuPause ();
      }
    }
    ApStartupSignalBuffer = PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal;
    //
    // Clear AP start-up signal
    //
    *ApStartupSignalBuffer = 0;
    while (TRUE) {
      DisableInterrupts ();
      if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {
        //
        // Place AP in Mwait-loop
        //
        AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0);
        if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
          //
          // If AP start-up signal is not set, place AP into
          // the maximum C-state
          //
          AsmMwait (PeiCpuMpData->ApTargetCState << 4, 0);
        }
      } else if (PeiCpuMpData->ApLoopMode == ApInRunLoop) {
        //
        // Place AP in Run-loop
        //
        CpuPause ();
      } else {
        ASSERT (FALSE);
      }

      //
      // If AP start-up signal is written, AP is waken up
      // otherwise place AP in loop again
      //
      if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
        break;
      }
    }
  }
}
EFIAPI
AcquireSpinLock (
  IN OUT  SPIN_LOCK                 *SpinLock
  )
{
  UINT64  Current;
  UINT64  Previous;
  UINT64  Total;
  UINT64  Start;
  UINT64  End;
  UINT64  Timeout;
  INT64   Cycle;
  INT64   Delta;

  if (PcdGet32 (PcdSpinLockTimeout) > 0) {
    //
    // Get the current timer value
    //
    Current = GetPerformanceCounter();

    //
    // Initialize local variables
    //
    Start = 0;
    End   = 0;
    Total = 0;

    //
    // Retrieve the performance counter properties and compute the number of performance
    // counter ticks required to reach the timeout
    //
    Timeout = DivU64x32 (
                MultU64x32 (
                  GetPerformanceCounterProperties (&Start, &End),
                  PcdGet32 (PcdSpinLockTimeout)
                  ),
                1000000
                );
    Cycle = End - Start;
    if (Cycle < 0) {
      Cycle = -Cycle;
    }
    Cycle++;

    while (!AcquireSpinLockOrFail (SpinLock)) {
      CpuPause ();
      Previous = Current;
      Current  = GetPerformanceCounter();
      Delta = (INT64) (Current - Previous);
      if (Start > End) {
        Delta = -Delta;
      }
      if (Delta < 0) {
        Delta += Cycle;
      }
      Total += Delta;
      ASSERT (Total < Timeout);
    }
  } else {
    while (!AcquireSpinLockOrFail (SpinLock)) {
      CpuPause ();
    }
  }
  return SpinLock;
}
Beispiel #18
0
/**
  Given timeout constraint, wait for all APs to arrive, and insure when this function returns, no AP will execute normal mode code before
  entering SMM, except SMI disabled APs.

**/
VOID
SmmWaitForApArrival (
  VOID
  )
{
  UINT64                            Timer;
  UINTN                             Index;

  ASSERT (mSmmMpSyncData->Counter <= mNumberOfCpus);

  //
  // Platform implementor should choose a timeout value appropriately:
  // - The timeout value should balance the SMM time constrains and the likelihood that delayed CPUs are excluded in the SMM run. Note
  //   the SMI Handlers must ALWAYS take into account the cases that not all APs are available in an SMI run.
  // - The timeout value must, in the case of 2nd timeout, be at least long enough to give time for all APs to receive the SMI IPI
  //   and either enter SMM or buffer the SMI, to insure there is no CPU running normal mode code when SMI handling starts. This will
  //   be TRUE even if a blocked CPU is brought out of the blocked state by a normal mode CPU (before the normal mode CPU received the
  //   SMI IPI), because with a buffered SMI, and CPU will enter SMM immediately after it is brought out of the blocked state.
  // - The timeout value must be longer than longest possible IO operation in the system
  //

  //
  // Sync with APs 1st timeout
  //
  for (Timer = StartSyncTimer ();
       !IsSyncTimerTimeout (Timer) &&
       !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED );
       ) {
    CpuPause ();
  }

  //
  // Not all APs have arrived, so we need 2nd round of timeout. IPIs should be sent to ALL none present APs,
  // because:
  // a) Delayed AP may have just come out of the delayed state. Blocked AP may have just been brought out of blocked state by some AP running
  //    normal mode code. These APs need to be guaranteed to have an SMI pending to insure that once they are out of delayed / blocked state, they
  //    enter SMI immediately without executing instructions in normal mode. Note traditional flow requires there are no APs doing normal mode
  //    work while SMI handling is on-going.
  // b) As a consequence of SMI IPI sending, (spurious) SMI may occur after this SMM run.
  // c) ** NOTE **: Use SMI disabling feature VERY CAREFULLY (if at all) for traditional flow, because a processor in SMI-disabled state
  //    will execute normal mode code, which breaks the traditional SMI handlers' assumption that no APs are doing normal
  //    mode work while SMI handling is on-going.
  // d) We don't add code to check SMI disabling status to skip sending IPI to SMI disabled APs, because:
  //    - In traditional flow, SMI disabling is discouraged.
  //    - In relaxed flow, CheckApArrival() will check SMI disabling status before calling this function.
  //    In both cases, adding SMI-disabling checking code increases overhead.
  //
  if (mSmmMpSyncData->Counter < mNumberOfCpus) {
    //
    // Send SMI IPIs to bring outside processors in
    //
    for (Index = mMaxNumberOfCpus; Index-- > 0;) {
      if (!mSmmMpSyncData->CpuData[Index].Present && gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) {
        SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId);
      }
    }

    //
    // Sync with APs 2nd timeout.
    //
    for (Timer = StartSyncTimer ();
         !IsSyncTimerTimeout (Timer) &&
         !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED );
         ) {
      CpuPause ();
    }
  }

  return;
}
Beispiel #19
0
/**
  Internal worker function for common exception handler.

  @param ExceptionType         Exception type.
  @param SystemContext         Pointer to EFI_SYSTEM_CONTEXT.
  @param ExceptionHandlerData  Pointer to exception handler data.
**/
VOID
CommonExceptionHandlerWorker (
  IN EFI_EXCEPTION_TYPE          ExceptionType, 
  IN EFI_SYSTEM_CONTEXT          SystemContext,
  IN EXCEPTION_HANDLER_DATA      *ExceptionHandlerData
  )
{
  EXCEPTION_HANDLER_CONTEXT      *ExceptionHandlerContext;
  RESERVED_VECTORS_DATA          *ReservedVectors;
  EFI_CPU_INTERRUPT_HANDLER      *ExternalInterruptHandler;

  ExceptionHandlerContext  = (EXCEPTION_HANDLER_CONTEXT *) (UINTN) (SystemContext.SystemContextIa32);
  ReservedVectors          = ExceptionHandlerData->ReservedVectors;
  ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;

  switch (ReservedVectors[ExceptionType].Attribute) {
  case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
    //
    // Need to jmp to old IDT handler after this exception handler
    //
    ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
    ExceptionHandlerContext->OldIdtHandler     = ReservedVectors[ExceptionType].ExceptonHandler;
    break;
  case EFI_VECTOR_HANDOFF_HOOK_AFTER:
    while (TRUE) {
      //
      // If if anyone has gotten SPIN_LOCK for owner running hook after
      //
      if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {
        //
        // Need to execute old IDT handler before running this exception handler
        //
        ReservedVectors[ExceptionType].ApicId = GetApicId ();
        ArchSaveExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);
        ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
        ExceptionHandlerContext->OldIdtHandler     = ReservedVectors[ExceptionType].ExceptonHandler;
        return;
      }
      //
      // If failed to acquire SPIN_LOCK, check if it was locked by processor itself
      //
      if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {
        //
        // Old IDT handler has been executed, then restore CPU exception content to
        // run new exception handler.
        //
        ArchRestoreExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);
        //
        // Rlease spin lock for ApicId
        //
        ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);
        break;
      }
      CpuPause ();
    }
    break;
  case 0xffffffff:
    break;
  default:
    //
    // It should never reach here
    //
    CpuDeadLoop ();
    break;
  }
  
  if (ExternalInterruptHandler != NULL &&
      ExternalInterruptHandler[ExceptionType] != NULL) {
    (ExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);
  } else if (ExceptionType < CPU_EXCEPTION_NUM) {
    //
    // Get Spinlock to display CPU information
    //
    while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {
      CpuPause ();
    }
    //
    // Display ExceptionType, CPU information and Image information
    //  
    DumpCpuContent (ExceptionType, SystemContext);
    //
    // Release Spinlock of output message
    //
    ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);
    //
    // Enter a dead loop if needn't to execute old IDT handler further
    //
    if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {
      CpuDeadLoop ();
    }
  }
}
Beispiel #20
0
/**
  SMI handler for AP.

  @param     CpuIndex         AP processor Index.
  @param     ValidSmi         Indicates that current SMI is a valid SMI or not.
  @param     SyncMode         SMM MP sync mode.

**/
VOID
APHandler (
  IN      UINTN                     CpuIndex,
  IN      BOOLEAN                   ValidSmi,
  IN      SMM_CPU_SYNC_MODE         SyncMode
  )
{
  UINT64                            Timer;
  UINTN                             BspIndex;
  MTRR_SETTINGS                     Mtrrs;

  //
  // Timeout BSP
  //
  for (Timer = StartSyncTimer ();
       !IsSyncTimerTimeout (Timer) &&
       !mSmmMpSyncData->InsideSmm;
       ) {
    CpuPause ();
  }

  if (!mSmmMpSyncData->InsideSmm) {
    //
    // BSP timeout in the first round
    //
    if (mSmmMpSyncData->BspIndex != -1) {
      //
      // BSP Index is known
      //
      BspIndex = mSmmMpSyncData->BspIndex;
      ASSERT (CpuIndex != BspIndex);

      //
      // Send SMI IPI to bring BSP in
      //
      SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[BspIndex].ProcessorId);

      //
      // Now clock BSP for the 2nd time
      //
      for (Timer = StartSyncTimer ();
           !IsSyncTimerTimeout (Timer) &&
           !mSmmMpSyncData->InsideSmm;
           ) {
        CpuPause ();
      }

      if (!mSmmMpSyncData->InsideSmm) {
        //
        // Give up since BSP is unable to enter SMM
        // and signal the completion of this AP
        WaitForSemaphore (&mSmmMpSyncData->Counter);
        return;
      }
    } else {
      //
      // Don't know BSP index. Give up without sending IPI to BSP.
      //
      WaitForSemaphore (&mSmmMpSyncData->Counter);
      return;
    }
  }

  //
  // BSP is available
  //
  BspIndex = mSmmMpSyncData->BspIndex;
  ASSERT (CpuIndex != BspIndex);

  //
  // Mark this processor's presence
  //
  mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE;

  if (SyncMode == SmmCpuSyncModeTradition || SmmCpuFeaturesNeedConfigureMtrrs()) {
    //
    // Notify BSP of arrival at this point
    //
    ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
  }

  if (SmmCpuFeaturesNeedConfigureMtrrs()) {
    //
    // Wait for the signal from BSP to backup MTRRs
    //
    WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);

    //
    // Backup OS MTRRs
    //
    MtrrGetAllMtrrs(&Mtrrs);

    //
    // Signal BSP the completion of this AP
    //
    ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);

    //
    // Wait for BSP's signal to program MTRRs
    //
    WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);

    //
    // Replace OS MTRRs with SMI MTRRs
    //
    ReplaceOSMtrrs (CpuIndex);

    //
    // Signal BSP the completion of this AP
    //
    ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
  }

  while (TRUE) {
    //
    // Wait for something to happen
    //
    WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);

    //
    // Check if BSP wants to exit SMM
    //
    if (!mSmmMpSyncData->InsideSmm) {
      break;
    }

    //
    // BUSY should be acquired by SmmStartupThisAp()
    //
    ASSERT (
      !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy)
      );

    //
    // Invoke the scheduled procedure
    //
    (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (
      (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
      );

    //
    // Release BUSY
    //
    ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);
  }

  if (SmmCpuFeaturesNeedConfigureMtrrs()) {
    //
    // Notify BSP the readiness of this AP to program MTRRs
    //
    ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);

    //
    // Wait for the signal from BSP to program MTRRs
    //
    WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);

    //
    // Restore OS MTRRs
    //
    SmmCpuFeaturesReenableSmrr ();
    MtrrSetAllMtrrs(&Mtrrs);
  }

  //
  // Notify BSP the readiness of this AP to Reset states/semaphore for this processor
  //
  ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);

  //
  // Wait for the signal from BSP to Reset states/semaphore for this processor
  //
  WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);

  //
  // Reset states/semaphore for this processor
  //
  mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE;

  //
  // Notify BSP the readiness of this AP to exit SMM
  //
  ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);

}