UefiCpuPkg/CpuMpPei: Remove unused files and codes
Cc: Michael Kinney <michael.d.kinney@intel.com> Cc: Feng Tian <feng.tian@intel.com> Cc: Giri P Mudusuru <giri.p.mudusuru@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jeff Fan <jeff.fan@intel.com> Reviewed-by: Michael Kinney <michael.d.kinney@intel.com> Tested-by: Laszlo Ersek <lersek@redhat.com> Tested-by: Michael Kinney <michael.d.kinney@intel.com>
This commit is contained in:
parent
a1a4c7a467
commit
4b0eeef313
@ -13,843 +13,6 @@
|
|||||||
**/
|
**/
|
||||||
|
|
||||||
#include "CpuMpPei.h"
|
#include "CpuMpPei.h"
|
||||||
|
|
||||||
GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
|
|
||||||
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
||||||
&gEfiEndOfPeiSignalPpiGuid,
|
|
||||||
CpuMpEndOfPeiCallback
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
Sort the APIC ID of all processors.
|
|
||||||
|
|
||||||
This function sorts the APIC ID of all processors so that processor number is
|
|
||||||
assigned in the ascending order of APIC ID which eases MP debugging.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
SortApicId (
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINTN Index1;
|
|
||||||
UINTN Index2;
|
|
||||||
UINTN Index3;
|
|
||||||
UINT32 ApicId;
|
|
||||||
PEI_CPU_DATA CpuData;
|
|
||||||
UINT32 ApCount;
|
|
||||||
|
|
||||||
ApCount = PeiCpuMpData->CpuCount - 1;
|
|
||||||
|
|
||||||
if (ApCount != 0) {
|
|
||||||
for (Index1 = 0; Index1 < ApCount; Index1++) {
|
|
||||||
Index3 = Index1;
|
|
||||||
//
|
|
||||||
// Sort key is the hardware default APIC ID
|
|
||||||
//
|
|
||||||
ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
|
|
||||||
for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
|
|
||||||
if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {
|
|
||||||
Index3 = Index2;
|
|
||||||
ApicId = PeiCpuMpData->CpuData[Index2].ApicId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Index3 != Index1) {
|
|
||||||
CopyMem (&CpuData, &PeiCpuMpData->CpuData[Index3], sizeof (PEI_CPU_DATA));
|
|
||||||
CopyMem (
|
|
||||||
&PeiCpuMpData->CpuData[Index3],
|
|
||||||
&PeiCpuMpData->CpuData[Index1],
|
|
||||||
sizeof (PEI_CPU_DATA)
|
|
||||||
);
|
|
||||||
CopyMem (&PeiCpuMpData->CpuData[Index1], &CpuData, sizeof (PEI_CPU_DATA));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Get the processor number for the BSP
|
|
||||||
//
|
|
||||||
ApicId = GetInitialApicId ();
|
|
||||||
for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {
|
|
||||||
if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {
|
|
||||||
PeiCpuMpData->BspNumber = (UINT32) Index1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Enable x2APIC mode on APs.
|
|
||||||
|
|
||||||
@param Buffer Pointer to private data buffer.
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
EFIAPI
|
|
||||||
ApFuncEnableX2Apic (
|
|
||||||
IN OUT VOID *Buffer
|
|
||||||
)
|
|
||||||
{
|
|
||||||
SetApicMode (LOCAL_APIC_MODE_X2APIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get AP loop mode.
|
|
||||||
|
|
||||||
@param MonitorFilterSize Returns the largest monitor-line size in bytes.
|
|
||||||
|
|
||||||
@return The AP loop mode.
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
UINT8
|
|
||||||
GetApLoopMode (
|
|
||||||
OUT UINT16 *MonitorFilterSize
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT8 ApLoopMode;
|
|
||||||
UINT32 RegEbx;
|
|
||||||
UINT32 RegEcx;
|
|
||||||
UINT32 RegEdx;
|
|
||||||
|
|
||||||
ASSERT (MonitorFilterSize != NULL);
|
|
||||||
|
|
||||||
ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
|
|
||||||
ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
|
|
||||||
if (ApLoopMode == ApInMwaitLoop) {
|
|
||||||
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx, NULL);
|
|
||||||
if ((RegEcx & BIT3) == 0) {
|
|
||||||
//
|
|
||||||
// If processor does not support MONITOR/MWAIT feature
|
|
||||||
// by CPUID.[EAX=01H]:ECX.BIT3, force AP in Hlt-loop mode
|
|
||||||
//
|
|
||||||
ApLoopMode = ApInHltLoop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ApLoopMode == ApInHltLoop) {
|
|
||||||
*MonitorFilterSize = 0;
|
|
||||||
} else if (ApLoopMode == ApInRunLoop) {
|
|
||||||
*MonitorFilterSize = sizeof (UINT32);
|
|
||||||
} else if (ApLoopMode == ApInMwaitLoop) {
|
|
||||||
//
|
|
||||||
// CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
|
|
||||||
// CPUID.[EAX=05H].EDX: C-states supported using MWAIT
|
|
||||||
//
|
|
||||||
AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &RegEbx, NULL, &RegEdx);
|
|
||||||
*MonitorFilterSize = RegEbx & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ApLoopMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get CPU MP Data pointer from the Guided HOB.
|
|
||||||
|
|
||||||
@return Pointer to Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
PEI_CPU_MP_DATA *
|
|
||||||
GetMpHobData (
|
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_HOB_GUID_TYPE *GuidHob;
|
|
||||||
VOID *DataInHob;
|
|
||||||
PEI_CPU_MP_DATA *CpuMpData;
|
|
||||||
|
|
||||||
CpuMpData = NULL;
|
|
||||||
GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
|
|
||||||
if (GuidHob != NULL) {
|
|
||||||
DataInHob = GET_GUID_HOB_DATA (GuidHob);
|
|
||||||
CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob);
|
|
||||||
}
|
|
||||||
ASSERT (CpuMpData != NULL);
|
|
||||||
return CpuMpData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Save the volatile registers required to be restored following INIT IPI.
|
|
||||||
|
|
||||||
@param VolatileRegisters Returns buffer saved the volatile resisters
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
SaveVolatileRegisters (
|
|
||||||
OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT32 RegEdx;
|
|
||||||
|
|
||||||
VolatileRegisters->Cr0 = AsmReadCr0 ();
|
|
||||||
VolatileRegisters->Cr3 = AsmReadCr3 ();
|
|
||||||
VolatileRegisters->Cr4 = AsmReadCr4 ();
|
|
||||||
|
|
||||||
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
|
|
||||||
if ((RegEdx & BIT2) != 0) {
|
|
||||||
//
|
|
||||||
// If processor supports Debugging Extensions feature
|
|
||||||
// by CPUID.[EAX=01H]:EDX.BIT2
|
|
||||||
//
|
|
||||||
VolatileRegisters->Dr0 = AsmReadDr0 ();
|
|
||||||
VolatileRegisters->Dr1 = AsmReadDr1 ();
|
|
||||||
VolatileRegisters->Dr2 = AsmReadDr2 ();
|
|
||||||
VolatileRegisters->Dr3 = AsmReadDr3 ();
|
|
||||||
VolatileRegisters->Dr6 = AsmReadDr6 ();
|
|
||||||
VolatileRegisters->Dr7 = AsmReadDr7 ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Restore the volatile registers following INIT IPI.
|
|
||||||
|
|
||||||
@param VolatileRegisters Pointer to volatile resisters
|
|
||||||
@param IsRestoreDr TRUE: Restore DRx if supported
|
|
||||||
FALSE: Do not restore DRx
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
RestoreVolatileRegisters (
|
|
||||||
IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
|
|
||||||
IN BOOLEAN IsRestoreDr
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT32 RegEdx;
|
|
||||||
|
|
||||||
AsmWriteCr0 (VolatileRegisters->Cr0);
|
|
||||||
AsmWriteCr3 (VolatileRegisters->Cr3);
|
|
||||||
AsmWriteCr4 (VolatileRegisters->Cr4);
|
|
||||||
|
|
||||||
if (IsRestoreDr) {
|
|
||||||
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
|
|
||||||
if ((RegEdx & BIT2) != 0) {
|
|
||||||
//
|
|
||||||
// If processor supports Debugging Extensions feature
|
|
||||||
// by CPUID.[EAX=01H]:EDX.BIT2
|
|
||||||
//
|
|
||||||
AsmWriteDr0 (VolatileRegisters->Dr0);
|
|
||||||
AsmWriteDr1 (VolatileRegisters->Dr1);
|
|
||||||
AsmWriteDr2 (VolatileRegisters->Dr2);
|
|
||||||
AsmWriteDr3 (VolatileRegisters->Dr3);
|
|
||||||
AsmWriteDr6 (VolatileRegisters->Dr6);
|
|
||||||
AsmWriteDr7 (VolatileRegisters->Dr7);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Find the current Processor number by APIC ID.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
@param ProcessorNumber Return the pocessor number found
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS ProcessorNumber is found and returned.
|
|
||||||
@retval EFI_NOT_FOUND ProcessorNumber is not found.
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
EFI_STATUS
|
|
||||||
GetProcessorNumber (
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData,
|
|
||||||
OUT UINTN *ProcessorNumber
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINTN TotalProcessorNumber;
|
|
||||||
UINTN Index;
|
|
||||||
|
|
||||||
TotalProcessorNumber = PeiCpuMpData->CpuCount;
|
|
||||||
for (Index = 0; Index < TotalProcessorNumber; Index ++) {
|
|
||||||
if (PeiCpuMpData->CpuData[Index].ApicId == GetInitialApicId ()) {
|
|
||||||
*ProcessorNumber = Index;
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return EFI_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
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
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
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);
|
|
||||||
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;
|
|
||||||
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) {
|
|
||||||
//
|
|
||||||
// Clear AP start-up signal when AP waken up
|
|
||||||
//
|
|
||||||
InterlockedCompareExchange32 (
|
|
||||||
(UINT32 *)ApStartupSignalBuffer,
|
|
||||||
WAKEUP_AP_SIGNAL,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Write AP start-up signal to wakeup AP.
|
|
||||||
|
|
||||||
@param ApStartupSignalBuffer Pointer to AP wakeup signal
|
|
||||||
**/
|
|
||||||
VOID
|
|
||||||
WriteStartupSignal (
|
|
||||||
IN volatile UINT32 *ApStartupSignalBuffer
|
|
||||||
)
|
|
||||||
{
|
|
||||||
*ApStartupSignalBuffer = WAKEUP_AP_SIGNAL;
|
|
||||||
//
|
|
||||||
// If AP is waken up, StartupApSignal should be cleared.
|
|
||||||
// Otherwise, write StartupApSignal again till AP waken up.
|
|
||||||
//
|
|
||||||
while (InterlockedCompareExchange32 (
|
|
||||||
(UINT32 *)ApStartupSignalBuffer,
|
|
||||||
WAKEUP_AP_SIGNAL,
|
|
||||||
WAKEUP_AP_SIGNAL
|
|
||||||
) != 0) {
|
|
||||||
CpuPause ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function will be called by BSP to wakeup AP.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
@param Broadcast TRUE: Send broadcast IPI to all APs
|
|
||||||
FALSE: Send IPI to AP by ApicId
|
|
||||||
@param ProcessorNumber The handle number of specified processor
|
|
||||||
@param Procedure The function to be invoked by AP
|
|
||||||
@param ProcedureArgument The argument to be passed into AP function
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
WakeUpAP (
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData,
|
|
||||||
IN BOOLEAN Broadcast,
|
|
||||||
IN UINTN ProcessorNumber,
|
|
||||||
IN EFI_AP_PROCEDURE Procedure, OPTIONAL
|
|
||||||
IN VOID *ProcedureArgument OPTIONAL
|
|
||||||
)
|
|
||||||
{
|
|
||||||
volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
|
|
||||||
UINTN Index;
|
|
||||||
|
|
||||||
PeiCpuMpData->ApFunction = (UINTN) Procedure;
|
|
||||||
PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;
|
|
||||||
PeiCpuMpData->FinishedCount = 0;
|
|
||||||
|
|
||||||
ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;
|
|
||||||
ExchangeInfo->Lock = 0;
|
|
||||||
ExchangeInfo->StackStart = PeiCpuMpData->Buffer;
|
|
||||||
ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;
|
|
||||||
ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;
|
|
||||||
ExchangeInfo->ModeOffset = PeiCpuMpData->AddressMap.ModeEntryOffset;
|
|
||||||
ExchangeInfo->Cr3 = AsmReadCr3 ();
|
|
||||||
ExchangeInfo->CodeSegment = AsmReadCs ();
|
|
||||||
ExchangeInfo->DataSegment = AsmReadDs ();
|
|
||||||
ExchangeInfo->CFunction = (UINTN) ApCFunction;
|
|
||||||
ExchangeInfo->NumApsExecuting = 0;
|
|
||||||
ExchangeInfo->PeiCpuMpData = PeiCpuMpData;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Get the BSP's data of GDT and IDT
|
|
||||||
//
|
|
||||||
AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
|
|
||||||
AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
|
|
||||||
|
|
||||||
if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) {
|
|
||||||
//
|
|
||||||
// Get AP target C-state each time when waking up AP,
|
|
||||||
// for it maybe updated by platform again
|
|
||||||
//
|
|
||||||
PeiCpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Wakeup APs per AP loop state
|
|
||||||
//
|
|
||||||
if (PeiCpuMpData->ApLoopMode == ApInHltLoop || PeiCpuMpData->InitFlag) {
|
|
||||||
if (Broadcast) {
|
|
||||||
SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
|
|
||||||
} else {
|
|
||||||
SendInitSipiSipi (
|
|
||||||
PeiCpuMpData->CpuData[ProcessorNumber].ApicId,
|
|
||||||
(UINT32) ExchangeInfo->BufferStart
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if ((PeiCpuMpData->ApLoopMode == ApInMwaitLoop) ||
|
|
||||||
(PeiCpuMpData->ApLoopMode == ApInRunLoop)) {
|
|
||||||
if (Broadcast) {
|
|
||||||
for (Index = 0; Index < PeiCpuMpData->CpuCount; Index++) {
|
|
||||||
if (Index != PeiCpuMpData->BspNumber) {
|
|
||||||
WriteStartupSignal (PeiCpuMpData->CpuData[Index].StartupApSignal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
WriteStartupSignal (PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ASSERT (FALSE);
|
|
||||||
}
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get available system memory below 1MB by specified size.
|
|
||||||
|
|
||||||
@param WakeupBufferSize Wakeup buffer size required
|
|
||||||
|
|
||||||
@retval other Return wakeup buffer address below 1MB.
|
|
||||||
@retval -1 Cannot find free memory below 1MB.
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
UINTN
|
|
||||||
GetWakeupBuffer (
|
|
||||||
IN UINTN WakeupBufferSize
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_PEI_HOB_POINTERS Hob;
|
|
||||||
UINTN WakeupBufferStart;
|
|
||||||
UINTN WakeupBufferEnd;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Get the HOB list for processing
|
|
||||||
//
|
|
||||||
Hob.Raw = GetHobList ();
|
|
||||||
|
|
||||||
//
|
|
||||||
// Collect memory ranges
|
|
||||||
//
|
|
||||||
while (!END_OF_HOB_LIST (Hob)) {
|
|
||||||
if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
|
|
||||||
if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
|
|
||||||
(Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
|
|
||||||
((Hob.ResourceDescriptor->ResourceAttribute &
|
|
||||||
(EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
|
|
||||||
EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
|
|
||||||
)) == 0)
|
|
||||||
) {
|
|
||||||
//
|
|
||||||
// Need memory under 1MB to be collected here
|
|
||||||
//
|
|
||||||
WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
|
|
||||||
if (WakeupBufferEnd > BASE_1MB) {
|
|
||||||
//
|
|
||||||
// Wakeup buffer should be under 1MB
|
|
||||||
//
|
|
||||||
WakeupBufferEnd = BASE_1MB;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Wakeup buffer should be aligned on 4KB
|
|
||||||
//
|
|
||||||
WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
|
|
||||||
if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Create a memory allocation HOB.
|
|
||||||
//
|
|
||||||
BuildMemoryAllocationHob (
|
|
||||||
WakeupBufferStart,
|
|
||||||
WakeupBufferSize,
|
|
||||||
EfiBootServicesData
|
|
||||||
);
|
|
||||||
return WakeupBufferStart;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Find the next HOB
|
|
||||||
//
|
|
||||||
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (UINTN) -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get available system memory below 1MB by specified size.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
BackupAndPrepareWakeupBuffer(
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData
|
|
||||||
)
|
|
||||||
{
|
|
||||||
CopyMem (
|
|
||||||
(VOID *) PeiCpuMpData->BackupBuffer,
|
|
||||||
(VOID *) PeiCpuMpData->WakeupBuffer,
|
|
||||||
PeiCpuMpData->BackupBufferSize
|
|
||||||
);
|
|
||||||
CopyMem (
|
|
||||||
(VOID *) PeiCpuMpData->WakeupBuffer,
|
|
||||||
(VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,
|
|
||||||
PeiCpuMpData->AddressMap.RendezvousFunnelSize
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Restore wakeup buffer data.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
RestoreWakeupBuffer(
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData
|
|
||||||
)
|
|
||||||
{
|
|
||||||
CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function will get CPU count in the system.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
|
|
||||||
@return AP processor count
|
|
||||||
**/
|
|
||||||
UINT32
|
|
||||||
CountProcessorNumber (
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData
|
|
||||||
)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// Load Microcode on BSP
|
|
||||||
//
|
|
||||||
MicrocodeDetect (PeiCpuMpData);
|
|
||||||
//
|
|
||||||
// Store BSP's MTRR setting
|
|
||||||
//
|
|
||||||
MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
|
|
||||||
//
|
|
||||||
if (PcdGet32 (PcdCpuMaxLogicalProcessorNumber) > 1) {
|
|
||||||
//
|
|
||||||
// Send 1st broadcast IPI to APs to wakeup APs
|
|
||||||
//
|
|
||||||
PeiCpuMpData->InitFlag = TRUE;
|
|
||||||
PeiCpuMpData->X2ApicEnable = FALSE;
|
|
||||||
WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);
|
|
||||||
//
|
|
||||||
// Wait for AP task to complete and then exit.
|
|
||||||
//
|
|
||||||
MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
|
|
||||||
PeiCpuMpData->InitFlag = FALSE;
|
|
||||||
PeiCpuMpData->CpuCount += (UINT32)PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;
|
|
||||||
ASSERT (PeiCpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
|
|
||||||
//
|
|
||||||
// Wait for all APs finished the initialization
|
|
||||||
//
|
|
||||||
while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {
|
|
||||||
CpuPause ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PeiCpuMpData->X2ApicEnable) {
|
|
||||||
DEBUG ((EFI_D_INFO, "Force x2APIC mode!\n"));
|
|
||||||
//
|
|
||||||
// Wakeup all APs to enable x2APIC mode
|
|
||||||
//
|
|
||||||
WakeUpAP (PeiCpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);
|
|
||||||
//
|
|
||||||
// Wait for all known APs finished
|
|
||||||
//
|
|
||||||
while (PeiCpuMpData->FinishedCount < (PeiCpuMpData->CpuCount - 1)) {
|
|
||||||
CpuPause ();
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Enable x2APIC on BSP
|
|
||||||
//
|
|
||||||
SetApicMode (LOCAL_APIC_MODE_X2APIC);
|
|
||||||
}
|
|
||||||
DEBUG ((EFI_D_INFO, "APIC MODE is %d\n", GetApicMode ()));
|
|
||||||
//
|
|
||||||
// Sort BSP/Aps by CPU APIC ID in ascending order
|
|
||||||
//
|
|
||||||
SortApicId (PeiCpuMpData);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));
|
|
||||||
return PeiCpuMpData->CpuCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Prepare for AP wakeup buffer and copy AP reset code into it.
|
|
||||||
|
|
||||||
Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
|
|
||||||
|
|
||||||
@return Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
PEI_CPU_MP_DATA *
|
|
||||||
PrepareAPStartupVector (
|
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
UINT32 MaxCpuCount;
|
|
||||||
PEI_CPU_MP_DATA *PeiCpuMpData;
|
|
||||||
EFI_PHYSICAL_ADDRESS Buffer;
|
|
||||||
UINTN BufferSize;
|
|
||||||
UINTN WakeupBuffer;
|
|
||||||
UINTN WakeupBufferSize;
|
|
||||||
MP_ASSEMBLY_ADDRESS_MAP AddressMap;
|
|
||||||
UINT8 ApLoopMode;
|
|
||||||
UINT16 MonitorFilterSize;
|
|
||||||
UINT8 *MonitorBuffer;
|
|
||||||
UINTN Index;
|
|
||||||
|
|
||||||
AsmGetAddressMap (&AddressMap);
|
|
||||||
WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
|
|
||||||
WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));
|
|
||||||
ASSERT (WakeupBuffer != (UINTN) -1);
|
|
||||||
DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));
|
|
||||||
|
|
||||||
//
|
|
||||||
// Allocate Pages for APs stack, CPU MP Data, backup buffer for wakeup buffer,
|
|
||||||
// and monitor buffer if required.
|
|
||||||
//
|
|
||||||
MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
|
|
||||||
BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)
|
|
||||||
+ WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;
|
|
||||||
ApLoopMode = GetApLoopMode (&MonitorFilterSize);
|
|
||||||
BufferSize += MonitorFilterSize * MaxCpuCount;
|
|
||||||
Status = PeiServicesAllocatePages (
|
|
||||||
EfiBootServicesData,
|
|
||||||
EFI_SIZE_TO_PAGES (BufferSize),
|
|
||||||
&Buffer
|
|
||||||
);
|
|
||||||
ASSERT_EFI_ERROR (Status);
|
|
||||||
|
|
||||||
PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);
|
|
||||||
PeiCpuMpData->Buffer = (UINTN) Buffer;
|
|
||||||
PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);
|
|
||||||
PeiCpuMpData->WakeupBuffer = WakeupBuffer;
|
|
||||||
PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);
|
|
||||||
PeiCpuMpData->BackupBufferSize = WakeupBufferSize;
|
|
||||||
PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);
|
|
||||||
|
|
||||||
PeiCpuMpData->CpuCount = 1;
|
|
||||||
PeiCpuMpData->BspNumber = 0;
|
|
||||||
PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->BackupBuffer +
|
|
||||||
PeiCpuMpData->BackupBufferSize);
|
|
||||||
PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
|
|
||||||
PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
|
|
||||||
PeiCpuMpData->EndOfPeiFlag = FALSE;
|
|
||||||
InitializeSpinLock(&PeiCpuMpData->MpLock);
|
|
||||||
SaveVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters);
|
|
||||||
CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
|
|
||||||
//
|
|
||||||
// Initialize AP loop mode
|
|
||||||
//
|
|
||||||
PeiCpuMpData->ApLoopMode = ApLoopMode;
|
|
||||||
DEBUG ((EFI_D_INFO, "AP Loop Mode is %d\n", PeiCpuMpData->ApLoopMode));
|
|
||||||
MonitorBuffer = (UINT8 *)(PeiCpuMpData->CpuData + MaxCpuCount);
|
|
||||||
if (PeiCpuMpData->ApLoopMode != ApInHltLoop) {
|
|
||||||
//
|
|
||||||
// Set up APs wakeup signal buffer
|
|
||||||
//
|
|
||||||
for (Index = 0; Index < MaxCpuCount; Index++) {
|
|
||||||
PeiCpuMpData->CpuData[Index].StartupApSignal =
|
|
||||||
(UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Backup original data and copy AP reset code in it
|
|
||||||
//
|
|
||||||
BackupAndPrepareWakeupBuffer(PeiCpuMpData);
|
|
||||||
|
|
||||||
return PeiCpuMpData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Notify function on End Of Pei PPI.
|
|
||||||
|
|
||||||
On S3 boot, this function will restore wakeup buffer data.
|
|
||||||
On normal boot, this function will flag wakeup buffer to be un-used type.
|
|
||||||
|
|
||||||
@param PeiServices The pointer to the PEI Services Table.
|
|
||||||
@param NotifyDescriptor Address of the notification descriptor data structure.
|
|
||||||
@param Ppi Address of the PPI that was installed.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS When everything is OK.
|
|
||||||
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
CpuMpEndOfPeiCallback (
|
|
||||||
IN EFI_PEI_SERVICES **PeiServices,
|
|
||||||
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
|
|
||||||
IN VOID *Ppi
|
|
||||||
)
|
|
||||||
{
|
|
||||||
EFI_STATUS Status;
|
|
||||||
EFI_BOOT_MODE BootMode;
|
|
||||||
PEI_CPU_MP_DATA *PeiCpuMpData;
|
|
||||||
EFI_PEI_HOB_POINTERS Hob;
|
|
||||||
EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
|
|
||||||
|
|
||||||
DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invoked\n"));
|
|
||||||
|
|
||||||
Status = PeiServicesGetBootMode (&BootMode);
|
|
||||||
ASSERT_EFI_ERROR (Status);
|
|
||||||
|
|
||||||
PeiCpuMpData = GetMpHobData ();
|
|
||||||
ASSERT (PeiCpuMpData != NULL);
|
|
||||||
|
|
||||||
if (BootMode != BOOT_ON_S3_RESUME) {
|
|
||||||
//
|
|
||||||
// Get the HOB list for processing
|
|
||||||
//
|
|
||||||
Hob.Raw = GetHobList ();
|
|
||||||
//
|
|
||||||
// Collect memory ranges
|
|
||||||
//
|
|
||||||
while (!END_OF_HOB_LIST (Hob)) {
|
|
||||||
if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
|
|
||||||
MemoryHob = Hob.MemoryAllocation;
|
|
||||||
if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {
|
|
||||||
//
|
|
||||||
// Flag this HOB type to un-used
|
|
||||||
//
|
|
||||||
GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Hob.Raw = GET_NEXT_HOB (Hob);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RestoreWakeupBuffer (PeiCpuMpData);
|
|
||||||
PeiCpuMpData->EndOfPeiFlag = TRUE;
|
|
||||||
}
|
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The Entry point of the MP CPU PEIM.
|
The Entry point of the MP CPU PEIM.
|
||||||
|
|
||||||
|
@ -21,258 +21,20 @@
|
|||||||
#include <Ppi/SecPlatformInformation.h>
|
#include <Ppi/SecPlatformInformation.h>
|
||||||
#include <Ppi/SecPlatformInformation2.h>
|
#include <Ppi/SecPlatformInformation2.h>
|
||||||
#include <Ppi/EndOfPeiPhase.h>
|
#include <Ppi/EndOfPeiPhase.h>
|
||||||
#include <Ppi/VectorHandoffInfo.h>
|
|
||||||
|
|
||||||
#include <Register/Cpuid.h>
|
|
||||||
#include <Register/LocalApic.h>
|
|
||||||
#include <Register/Msr.h>
|
|
||||||
|
|
||||||
#include <Library/BaseLib.h>
|
#include <Library/BaseLib.h>
|
||||||
#include <Library/BaseMemoryLib.h>
|
|
||||||
#include <Library/DebugLib.h>
|
#include <Library/DebugLib.h>
|
||||||
#include <Library/HobLib.h>
|
#include <Library/HobLib.h>
|
||||||
#include <Library/LocalApicLib.h>
|
#include <Library/LocalApicLib.h>
|
||||||
#include <Library/MtrrLib.h>
|
|
||||||
#include <Library/PcdLib.h>
|
|
||||||
#include <Library/PeimEntryPoint.h>
|
#include <Library/PeimEntryPoint.h>
|
||||||
#include <Library/PeiServicesLib.h>
|
#include <Library/PeiServicesLib.h>
|
||||||
#include <Library/ReportStatusCodeLib.h>
|
#include <Library/ReportStatusCodeLib.h>
|
||||||
#include <Library/SynchronizationLib.h>
|
|
||||||
#include <Library/TimerLib.h>
|
|
||||||
#include <Library/UefiCpuLib.h>
|
|
||||||
#include <Library/CpuLib.h>
|
|
||||||
#include <Library/CpuExceptionHandlerLib.h>
|
#include <Library/CpuExceptionHandlerLib.h>
|
||||||
#include <Library/MpInitLib.h>
|
#include <Library/MpInitLib.h>
|
||||||
|
|
||||||
#include "Microcode.h"
|
|
||||||
|
|
||||||
//
|
|
||||||
// AP state
|
|
||||||
//
|
|
||||||
typedef enum {
|
|
||||||
CpuStateIdle,
|
|
||||||
CpuStateBusy,
|
|
||||||
CpuStateDisabled
|
|
||||||
} CPU_STATE;
|
|
||||||
|
|
||||||
#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P')
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ApInHltLoop = 1,
|
|
||||||
ApInMwaitLoop = 2,
|
|
||||||
ApInRunLoop = 3
|
|
||||||
} AP_LOOP_MODE;
|
|
||||||
|
|
||||||
//
|
|
||||||
// AP reset code information
|
|
||||||
//
|
|
||||||
typedef struct {
|
|
||||||
UINT8 *RendezvousFunnelAddress;
|
|
||||||
UINTN ModeEntryOffset;
|
|
||||||
UINTN RendezvousFunnelSize;
|
|
||||||
} MP_ASSEMBLY_ADDRESS_MAP;
|
|
||||||
|
|
||||||
//
|
|
||||||
// CPU exchange information for switch BSP
|
|
||||||
//
|
|
||||||
typedef struct {
|
|
||||||
UINT8 State; // offset 0
|
|
||||||
UINTN StackPointer; // offset 4 / 8
|
|
||||||
IA32_DESCRIPTOR Gdtr; // offset 8 / 16
|
|
||||||
IA32_DESCRIPTOR Idtr; // offset 14 / 26
|
|
||||||
} CPU_EXCHANGE_ROLE_INFO;
|
|
||||||
|
|
||||||
typedef struct _PEI_CPU_MP_DATA PEI_CPU_MP_DATA;
|
|
||||||
|
|
||||||
#pragma pack(1)
|
|
||||||
|
|
||||||
//
|
|
||||||
// MP CPU exchange information for AP reset code
|
|
||||||
// This structure is required to be packed because fixed field offsets
|
|
||||||
// into this structure are used in assembly code in this module
|
|
||||||
//
|
|
||||||
typedef struct {
|
|
||||||
UINTN Lock;
|
|
||||||
UINTN StackStart;
|
|
||||||
UINTN StackSize;
|
|
||||||
UINTN CFunction;
|
|
||||||
IA32_DESCRIPTOR GdtrProfile;
|
|
||||||
IA32_DESCRIPTOR IdtrProfile;
|
|
||||||
UINTN BufferStart;
|
|
||||||
UINTN ModeOffset;
|
|
||||||
UINTN NumApsExecuting;
|
|
||||||
UINTN CodeSegment;
|
|
||||||
UINTN DataSegment;
|
|
||||||
UINTN Cr3;
|
|
||||||
PEI_CPU_MP_DATA *PeiCpuMpData;
|
|
||||||
} MP_CPU_EXCHANGE_INFO;
|
|
||||||
|
|
||||||
#pragma pack()
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
UINTN Cr0;
|
|
||||||
UINTN Cr3;
|
|
||||||
UINTN Cr4;
|
|
||||||
UINTN Dr0;
|
|
||||||
UINTN Dr1;
|
|
||||||
UINTN Dr2;
|
|
||||||
UINTN Dr3;
|
|
||||||
UINTN Dr6;
|
|
||||||
UINTN Dr7;
|
|
||||||
} CPU_VOLATILE_REGISTERS;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
volatile UINT32 *StartupApSignal;
|
|
||||||
UINT32 ApicId;
|
|
||||||
EFI_HEALTH_FLAGS Health;
|
|
||||||
CPU_STATE State;
|
|
||||||
BOOLEAN CpuHealthy;
|
|
||||||
CPU_VOLATILE_REGISTERS VolatileRegisters;
|
|
||||||
} PEI_CPU_DATA;
|
|
||||||
|
|
||||||
//
|
|
||||||
// PEI CPU MP Data save in memory
|
|
||||||
//
|
|
||||||
struct _PEI_CPU_MP_DATA {
|
|
||||||
SPIN_LOCK MpLock;
|
|
||||||
UINT32 CpuCount;
|
|
||||||
UINT32 BspNumber;
|
|
||||||
UINTN Buffer;
|
|
||||||
UINTN CpuApStackSize;
|
|
||||||
MP_ASSEMBLY_ADDRESS_MAP AddressMap;
|
|
||||||
UINTN WakeupBuffer;
|
|
||||||
UINTN BackupBuffer;
|
|
||||||
UINTN BackupBufferSize;
|
|
||||||
UINTN ApFunction;
|
|
||||||
UINTN ApFunctionArgument;
|
|
||||||
volatile UINT32 FinishedCount;
|
|
||||||
BOOLEAN EndOfPeiFlag;
|
|
||||||
BOOLEAN InitFlag;
|
|
||||||
BOOLEAN X2ApicEnable;
|
|
||||||
CPU_EXCHANGE_ROLE_INFO BSPInfo;
|
|
||||||
CPU_EXCHANGE_ROLE_INFO APInfo;
|
|
||||||
MTRR_SETTINGS MtrrTable;
|
|
||||||
UINT8 ApLoopMode;
|
|
||||||
UINT8 ApTargetCState;
|
|
||||||
PEI_CPU_DATA *CpuData;
|
|
||||||
volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
|
|
||||||
};
|
|
||||||
extern EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc;
|
extern EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Assembly code to get starting address and size of the rendezvous entry for APs.
|
|
||||||
Information for fixing a jump instruction in the code is also returned.
|
|
||||||
|
|
||||||
@param AddressMap Output buffer for address map information.
|
|
||||||
**/
|
|
||||||
VOID
|
|
||||||
EFIAPI
|
|
||||||
AsmGetAddressMap (
|
|
||||||
OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Assembly code to load GDT table and update segment accordingly.
|
|
||||||
|
|
||||||
@param Gdtr Pointer to GDT descriptor
|
|
||||||
**/
|
|
||||||
VOID
|
|
||||||
EFIAPI
|
|
||||||
AsmInitializeGdt (
|
|
||||||
IN IA32_DESCRIPTOR *Gdtr
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get available system memory below 1MB by specified size.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
BackupAndPrepareWakeupBuffer(
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Restore wakeup buffer data.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
RestoreWakeupBuffer(
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Notify function on End Of Pei PPI.
|
|
||||||
|
|
||||||
On S3 boot, this function will restore wakeup buffer data.
|
|
||||||
On normal boot, this function will flag wakeup buffer to be un-used type.
|
|
||||||
|
|
||||||
@param PeiServices The pointer to the PEI Services Table.
|
|
||||||
@param NotifyDescriptor Address of the notification descriptor data structure.
|
|
||||||
@param Ppi Address of the PPI that was installed.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS When everything is OK.
|
|
||||||
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
EFI_STATUS
|
|
||||||
EFIAPI
|
|
||||||
CpuMpEndOfPeiCallback (
|
|
||||||
IN EFI_PEI_SERVICES **PeiServices,
|
|
||||||
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
|
|
||||||
IN VOID *Ppi
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function will be called by BSP to wakeup AP.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
@param Broadcast TRUE: Send broadcast IPI to all APs
|
|
||||||
FALSE: Send IPI to AP by ApicId
|
|
||||||
@param ProcessorNumber The handle number of specified processor
|
|
||||||
@param Procedure The function to be invoked by AP
|
|
||||||
@param ProcedureArgument The argument to be passed into AP function
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
WakeUpAP (
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData,
|
|
||||||
IN BOOLEAN Broadcast,
|
|
||||||
IN UINTN ProcessorNumber,
|
|
||||||
IN EFI_AP_PROCEDURE Procedure, OPTIONAL
|
|
||||||
IN VOID *ProcedureArgument OPTIONAL
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get CPU MP Data pointer from the Guided HOB.
|
|
||||||
|
|
||||||
@return Pointer to Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
PEI_CPU_MP_DATA *
|
|
||||||
GetMpHobData (
|
|
||||||
VOID
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Find the current Processor number by APIC ID.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
@param ProcessorNumber Return the pocessor number found
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS ProcessorNumber is found and returned.
|
|
||||||
@retval EFI_NOT_FOUND ProcessorNumber is not found.
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
EFI_STATUS
|
|
||||||
GetProcessorNumber (
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData,
|
|
||||||
OUT UINTN *ProcessorNumber
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Collects BIST data from PPI.
|
Collects BIST data from PPI.
|
||||||
|
|
||||||
@ -307,14 +69,4 @@ SecPlatformInformation2 (
|
|||||||
OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2
|
OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
Detect whether specified processor can find matching microcode patch and load it.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
VOID
|
|
||||||
MicrocodeDetect (
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData
|
|
||||||
);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,21 +31,9 @@
|
|||||||
CpuMpPei.h
|
CpuMpPei.h
|
||||||
CpuMpPei.c
|
CpuMpPei.c
|
||||||
CpuBist.c
|
CpuBist.c
|
||||||
Microcode.h
|
|
||||||
Microcode.c
|
|
||||||
PeiMpServices.h
|
PeiMpServices.h
|
||||||
PeiMpServices.c
|
PeiMpServices.c
|
||||||
|
|
||||||
[Sources.IA32]
|
|
||||||
Ia32/MpEqu.inc
|
|
||||||
Ia32/MpFuncs.asm
|
|
||||||
Ia32/MpFuncs.nasm
|
|
||||||
|
|
||||||
[Sources.X64]
|
|
||||||
X64/MpEqu.inc
|
|
||||||
X64/MpFuncs.asm
|
|
||||||
X64/MpFuncs.nasm
|
|
||||||
|
|
||||||
[Packages]
|
[Packages]
|
||||||
MdePkg/MdePkg.dec
|
MdePkg/MdePkg.dec
|
||||||
MdeModulePkg/MdeModulePkg.dec
|
MdeModulePkg/MdeModulePkg.dec
|
||||||
@ -53,40 +41,23 @@
|
|||||||
|
|
||||||
[LibraryClasses]
|
[LibraryClasses]
|
||||||
BaseLib
|
BaseLib
|
||||||
BaseMemoryLib
|
|
||||||
DebugLib
|
DebugLib
|
||||||
HobLib
|
HobLib
|
||||||
LocalApicLib
|
LocalApicLib
|
||||||
MtrrLib
|
|
||||||
PcdLib
|
|
||||||
PeimEntryPoint
|
PeimEntryPoint
|
||||||
PeiServicesLib
|
PeiServicesLib
|
||||||
ReportStatusCodeLib
|
ReportStatusCodeLib
|
||||||
SynchronizationLib
|
|
||||||
TimerLib
|
|
||||||
UefiCpuLib
|
|
||||||
CpuLib
|
|
||||||
CpuExceptionHandlerLib
|
CpuExceptionHandlerLib
|
||||||
MpInitLib
|
MpInitLib
|
||||||
|
|
||||||
[Ppis]
|
[Ppis]
|
||||||
gEfiPeiMpServicesPpiGuid ## PRODUCES
|
gEfiPeiMpServicesPpiGuid ## PRODUCES
|
||||||
gEfiEndOfPeiSignalPpiGuid ## NOTIFY
|
|
||||||
gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES
|
gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES
|
||||||
## SOMETIMES_CONSUMES
|
## SOMETIMES_CONSUMES
|
||||||
## SOMETIMES_PRODUCES
|
## SOMETIMES_PRODUCES
|
||||||
gEfiSecPlatformInformation2PpiGuid
|
gEfiSecPlatformInformation2PpiGuid
|
||||||
gEfiVectorHandoffInfoPpiGuid ## SOMETIMES_CONSUMES
|
gEfiVectorHandoffInfoPpiGuid ## SOMETIMES_CONSUMES
|
||||||
|
|
||||||
[Pcd]
|
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES
|
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## CONSUMES
|
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES
|
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES
|
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES
|
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
|
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
|
|
||||||
|
|
||||||
[Depex]
|
[Depex]
|
||||||
gEfiPeiMemoryDiscoveredPpiGuid
|
gEfiPeiMemoryDiscoveredPpiGuid
|
||||||
|
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
;------------------------------------------------------------------------------ ;
|
|
||||||
; Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
||||||
; This program and the accompanying materials
|
|
||||||
; are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
; which accompanies this distribution. The full text of the license may be found at
|
|
||||||
; http://opensource.org/licenses/bsd-license.php.
|
|
||||||
;
|
|
||||||
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
;
|
|
||||||
; Module Name:
|
|
||||||
;
|
|
||||||
; MpEqu.inc
|
|
||||||
;
|
|
||||||
; Abstract:
|
|
||||||
;
|
|
||||||
; This is the equates file for Multiple Processor support
|
|
||||||
;
|
|
||||||
;-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
VacantFlag equ 00h
|
|
||||||
NotVacantFlag equ 0ffh
|
|
||||||
|
|
||||||
CPU_SWITCH_STATE_IDLE equ 0
|
|
||||||
CPU_SWITCH_STATE_STORED equ 1
|
|
||||||
CPU_SWITCH_STATE_LOADED equ 2
|
|
||||||
|
|
||||||
LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
|
|
||||||
StackStartAddressLocation equ LockLocation + 04h
|
|
||||||
StackSizeLocation equ LockLocation + 08h
|
|
||||||
ApProcedureLocation equ LockLocation + 0Ch
|
|
||||||
GdtrLocation equ LockLocation + 10h
|
|
||||||
IdtrLocation equ LockLocation + 16h
|
|
||||||
BufferStartLocation equ LockLocation + 1Ch
|
|
||||||
ModeOffsetLocation equ LockLocation + 20h
|
|
||||||
NumApsExecutingLoction equ LockLocation + 24h
|
|
||||||
CodeSegmentLocation equ LockLocation + 28h
|
|
||||||
DataSegmentLocation equ LockLocation + 2Ch
|
|
||||||
|
|
@ -1,250 +0,0 @@
|
|||||||
;------------------------------------------------------------------------------ ;
|
|
||||||
; Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
||||||
; This program and the accompanying materials
|
|
||||||
; are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
; which accompanies this distribution. The full text of the license may be found at
|
|
||||||
; http://opensource.org/licenses/bsd-license.php.
|
|
||||||
;
|
|
||||||
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
;
|
|
||||||
; Module Name:
|
|
||||||
;
|
|
||||||
; MpFuncs32.asm
|
|
||||||
;
|
|
||||||
; Abstract:
|
|
||||||
;
|
|
||||||
; This is the assembly code for MP support
|
|
||||||
;
|
|
||||||
;-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
.686p
|
|
||||||
.model flat
|
|
||||||
|
|
||||||
include MpEqu.inc
|
|
||||||
InitializeFloatingPointUnits PROTO C
|
|
||||||
|
|
||||||
.code
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
|
|
||||||
;procedure serializes all the AP processors through an Init sequence. It must be
|
|
||||||
;noted that APs arrive here very raw...ie: real mode, no stack.
|
|
||||||
;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
|
|
||||||
;IS IN MACHINE CODE.
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
RendezvousFunnelProc PROC PUBLIC
|
|
||||||
RendezvousFunnelProcStart::
|
|
||||||
; At this point CS = 0x(vv00) and ip= 0x0.
|
|
||||||
; Save BIST information to ebp firstly
|
|
||||||
db 66h, 08bh, 0e8h ; mov ebp, eax ; save BIST information
|
|
||||||
|
|
||||||
db 8ch,0c8h ; mov ax, cs
|
|
||||||
db 8eh,0d8h ; mov ds, ax
|
|
||||||
db 8eh,0c0h ; mov es, ax
|
|
||||||
db 8eh,0d0h ; mov ss, ax
|
|
||||||
db 33h,0c0h ; xor ax, ax
|
|
||||||
db 8eh,0e0h ; mov fs, ax
|
|
||||||
db 8eh,0e8h ; mov gs, ax
|
|
||||||
|
|
||||||
db 0BEh ; opcode of mov si, mem16
|
|
||||||
dw BufferStartLocation ; mov si, BufferStartLocation
|
|
||||||
db 66h, 8Bh, 1Ch ; mov ebx, dword ptr [si]
|
|
||||||
|
|
||||||
db 0BEh ; opcode of mov si, mem16
|
|
||||||
dw ModeOffsetLocation ; mov si, ModeOffsetLocation
|
|
||||||
db 66h, 8Bh, 04h ; mov eax, [si]
|
|
||||||
db 0BEh ; opcode of mov si, mem16
|
|
||||||
dw CodeSegmentLocation ; mov si, CodeSegmentLocation
|
|
||||||
db 66h, 8Bh, 14h ; mov edx, [si]
|
|
||||||
db 89h, 0C7h ; mov di, ax
|
|
||||||
db 83h, 0EFh, 02h ; sub di, 02h
|
|
||||||
db 89h, 15h ; mov [di], dx
|
|
||||||
db 83h, 0EFh, 04h ; sub di, 04h
|
|
||||||
db 66h, 01h, 0D8h ; add eax, ebx
|
|
||||||
db 66h, 89h, 05h ; mov [di], eax
|
|
||||||
|
|
||||||
db 0BEh ; opcode of mov si, mem16
|
|
||||||
dw DataSegmentLocation ; mov si, DataSegmentLocation
|
|
||||||
db 66h, 8Bh, 14h ; mov edx, [si]
|
|
||||||
|
|
||||||
db 0BEh ; opcode of mov si, mem16
|
|
||||||
dw GdtrLocation ; mov si, GdtrLocation
|
|
||||||
db 66h ; db 66h
|
|
||||||
db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
|
|
||||||
|
|
||||||
db 0BEh
|
|
||||||
dw IdtrLocation ; mov si, IdtrLocation
|
|
||||||
db 66h ; db 66h
|
|
||||||
db 2Eh,0Fh, 01h, 1Ch ; lidt fword ptr cs:[si]
|
|
||||||
|
|
||||||
db 33h, 0C0h ; xor ax, ax
|
|
||||||
db 8Eh, 0D8h ; mov ds, ax
|
|
||||||
|
|
||||||
db 0Fh, 20h, 0C0h ; mov eax, cr0 ;Get control register 0
|
|
||||||
db 66h, 83h, 0C8h, 03h ; or eax, 000000003h ;Set PE bit (bit #0) & MP
|
|
||||||
db 0Fh, 22h, 0C0h ; mov cr0, eax
|
|
||||||
|
|
||||||
db 66h, 67h, 0EAh ; far jump
|
|
||||||
dd 0h ; 32-bit offset
|
|
||||||
dw 0h ; 16-bit selector
|
|
||||||
|
|
||||||
Flat32Start:: ; protected mode entry point
|
|
||||||
mov ds, dx
|
|
||||||
mov es, dx
|
|
||||||
mov fs, dx
|
|
||||||
mov gs, dx
|
|
||||||
mov ss, dx
|
|
||||||
|
|
||||||
mov esi, ebx
|
|
||||||
mov edi, esi
|
|
||||||
add edi, LockLocation
|
|
||||||
mov eax, NotVacantFlag
|
|
||||||
|
|
||||||
TestLock:
|
|
||||||
xchg dword ptr [edi], eax
|
|
||||||
cmp eax, NotVacantFlag
|
|
||||||
jz TestLock
|
|
||||||
|
|
||||||
mov edi, esi
|
|
||||||
add edi, NumApsExecutingLoction
|
|
||||||
inc dword ptr [edi]
|
|
||||||
mov ebx, dword ptr [edi]
|
|
||||||
|
|
||||||
ProgramStack:
|
|
||||||
mov edi, esi
|
|
||||||
add edi, StackSizeLocation
|
|
||||||
mov eax, dword ptr [edi]
|
|
||||||
mov edi, esi
|
|
||||||
add edi, StackStartAddressLocation
|
|
||||||
add eax, dword ptr [edi]
|
|
||||||
mov esp, eax
|
|
||||||
mov dword ptr [edi], eax
|
|
||||||
|
|
||||||
Releaselock:
|
|
||||||
mov eax, VacantFlag
|
|
||||||
mov edi, esi
|
|
||||||
add edi, LockLocation
|
|
||||||
xchg dword ptr [edi], eax
|
|
||||||
|
|
||||||
CProcedureInvoke:
|
|
||||||
push ebp ; push BIST data at top of AP stack
|
|
||||||
xor ebp, ebp ; clear ebp for call stack trace
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
|
|
||||||
mov eax, InitializeFloatingPointUnits
|
|
||||||
call eax ; Call assembly function to initialize FPU per UEFI spec
|
|
||||||
|
|
||||||
push ebx ; Push NumApsExecuting
|
|
||||||
mov eax, esi
|
|
||||||
add eax, LockLocation
|
|
||||||
push eax ; push address of exchange info data buffer
|
|
||||||
|
|
||||||
mov edi, esi
|
|
||||||
add edi, ApProcedureLocation
|
|
||||||
mov eax, dword ptr [edi]
|
|
||||||
|
|
||||||
call eax ; invoke C function
|
|
||||||
|
|
||||||
jmp $ ; never reach here
|
|
||||||
|
|
||||||
RendezvousFunnelProc ENDP
|
|
||||||
RendezvousFunnelProcEnd::
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
; AsmGetAddressMap (&AddressMap);
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
AsmGetAddressMap PROC near C PUBLIC
|
|
||||||
pushad
|
|
||||||
mov ebp,esp
|
|
||||||
|
|
||||||
mov ebx, dword ptr [ebp+24h]
|
|
||||||
mov dword ptr [ebx], RendezvousFunnelProcStart
|
|
||||||
mov dword ptr [ebx + 4h], Flat32Start - RendezvousFunnelProcStart
|
|
||||||
mov dword ptr [ebx + 8h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
|
|
||||||
|
|
||||||
popad
|
|
||||||
ret
|
|
||||||
AsmGetAddressMap ENDP
|
|
||||||
|
|
||||||
PAUSE32 MACRO
|
|
||||||
DB 0F3h
|
|
||||||
DB 090h
|
|
||||||
ENDM
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
|
|
||||||
;about to become an AP. It switches it'stack with the current AP.
|
|
||||||
;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
AsmExchangeRole PROC near C PUBLIC
|
|
||||||
; DO NOT call other functions in this function, since 2 CPU may use 1 stack
|
|
||||||
; at the same time. If 1 CPU try to call a function, stack will be corrupted.
|
|
||||||
pushad
|
|
||||||
mov ebp,esp
|
|
||||||
|
|
||||||
; esi contains MyInfo pointer
|
|
||||||
mov esi, dword ptr [ebp+24h]
|
|
||||||
|
|
||||||
; edi contains OthersInfo pointer
|
|
||||||
mov edi, dword ptr [ebp+28h]
|
|
||||||
|
|
||||||
;Store EFLAGS, GDTR and IDTR register to stack
|
|
||||||
pushfd
|
|
||||||
mov eax, cr4
|
|
||||||
push eax ; push cr4 firstly
|
|
||||||
mov eax, cr0
|
|
||||||
push eax
|
|
||||||
|
|
||||||
sgdt fword ptr [esi+8]
|
|
||||||
sidt fword ptr [esi+14]
|
|
||||||
|
|
||||||
; Store the its StackPointer
|
|
||||||
mov dword ptr [esi+4],esp
|
|
||||||
|
|
||||||
; update its switch state to STORED
|
|
||||||
mov byte ptr [esi], CPU_SWITCH_STATE_STORED
|
|
||||||
|
|
||||||
WaitForOtherStored:
|
|
||||||
; wait until the other CPU finish storing its state
|
|
||||||
cmp byte ptr [edi], CPU_SWITCH_STATE_STORED
|
|
||||||
jz OtherStored
|
|
||||||
PAUSE32
|
|
||||||
jmp WaitForOtherStored
|
|
||||||
|
|
||||||
OtherStored:
|
|
||||||
; Since another CPU already stored its state, load them
|
|
||||||
; load GDTR value
|
|
||||||
lgdt fword ptr [edi+8]
|
|
||||||
|
|
||||||
; load IDTR value
|
|
||||||
lidt fword ptr [edi+14]
|
|
||||||
|
|
||||||
; load its future StackPointer
|
|
||||||
mov esp, dword ptr [edi+4]
|
|
||||||
|
|
||||||
; update the other CPU's switch state to LOADED
|
|
||||||
mov byte ptr [edi], CPU_SWITCH_STATE_LOADED
|
|
||||||
|
|
||||||
WaitForOtherLoaded:
|
|
||||||
; wait until the other CPU finish loading new state,
|
|
||||||
; otherwise the data in stack may corrupt
|
|
||||||
cmp byte ptr [esi], CPU_SWITCH_STATE_LOADED
|
|
||||||
jz OtherLoaded
|
|
||||||
PAUSE32
|
|
||||||
jmp WaitForOtherLoaded
|
|
||||||
|
|
||||||
OtherLoaded:
|
|
||||||
; since the other CPU already get the data it want, leave this procedure
|
|
||||||
pop eax
|
|
||||||
mov cr0, eax
|
|
||||||
pop eax
|
|
||||||
mov cr4, eax
|
|
||||||
popfd
|
|
||||||
|
|
||||||
popad
|
|
||||||
ret
|
|
||||||
AsmExchangeRole ENDP
|
|
||||||
|
|
||||||
END
|
|
@ -1,229 +0,0 @@
|
|||||||
;------------------------------------------------------------------------------ ;
|
|
||||||
; Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
||||||
; This program and the accompanying materials
|
|
||||||
; are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
; which accompanies this distribution. The full text of the license may be found at
|
|
||||||
; http://opensource.org/licenses/bsd-license.php.
|
|
||||||
;
|
|
||||||
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
;
|
|
||||||
; Module Name:
|
|
||||||
;
|
|
||||||
; MpFuncs.nasm
|
|
||||||
;
|
|
||||||
; Abstract:
|
|
||||||
;
|
|
||||||
; This is the assembly code for MP support
|
|
||||||
;
|
|
||||||
;-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
%include "MpEqu.inc"
|
|
||||||
extern ASM_PFX(InitializeFloatingPointUnits)
|
|
||||||
|
|
||||||
SECTION .text
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
|
|
||||||
;procedure serializes all the AP processors through an Init sequence. It must be
|
|
||||||
;noted that APs arrive here very raw...ie: real mode, no stack.
|
|
||||||
;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
|
|
||||||
;IS IN MACHINE CODE.
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
global ASM_PFX(RendezvousFunnelProc)
|
|
||||||
ASM_PFX(RendezvousFunnelProc):
|
|
||||||
RendezvousFunnelProcStart:
|
|
||||||
; At this point CS = 0x(vv00) and ip= 0x0.
|
|
||||||
BITS 16
|
|
||||||
mov ebp, eax ; save BIST information
|
|
||||||
|
|
||||||
mov ax, cs
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov ss, ax
|
|
||||||
xor ax, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
mov si, BufferStartLocation
|
|
||||||
mov ebx, [si]
|
|
||||||
|
|
||||||
mov si, ModeOffsetLocation
|
|
||||||
mov eax, [si]
|
|
||||||
mov si, CodeSegmentLocation
|
|
||||||
mov edx, [si]
|
|
||||||
mov di, ax
|
|
||||||
sub di, 02h
|
|
||||||
mov [di], dx
|
|
||||||
sub di, 04h
|
|
||||||
add eax, ebx
|
|
||||||
mov [di],eax
|
|
||||||
|
|
||||||
mov si, DataSegmentLocation
|
|
||||||
mov edx, [si]
|
|
||||||
|
|
||||||
mov si, GdtrLocation
|
|
||||||
o32 lgdt [cs:si]
|
|
||||||
|
|
||||||
mov si, IdtrLocation
|
|
||||||
o32 lidt [cs:si]
|
|
||||||
|
|
||||||
xor ax, ax
|
|
||||||
mov ds, ax
|
|
||||||
|
|
||||||
mov eax, cr0 ;Get control register 0
|
|
||||||
or eax, 000000003h ;Set PE bit (bit #0) & MP
|
|
||||||
mov cr0, eax
|
|
||||||
|
|
||||||
jmp 0:strict dword 0 ; far jump to protected mode
|
|
||||||
BITS 32
|
|
||||||
Flat32Start: ; protected mode entry point
|
|
||||||
mov ds, dx
|
|
||||||
mov es, dx
|
|
||||||
mov fs, dx
|
|
||||||
mov gs, dx
|
|
||||||
mov ss, dx
|
|
||||||
|
|
||||||
mov esi, ebx
|
|
||||||
mov edi, esi
|
|
||||||
add edi, LockLocation
|
|
||||||
mov eax, NotVacantFlag
|
|
||||||
|
|
||||||
TestLock:
|
|
||||||
xchg [edi], eax
|
|
||||||
cmp eax, NotVacantFlag
|
|
||||||
jz TestLock
|
|
||||||
|
|
||||||
mov edi, esi
|
|
||||||
add edi, NumApsExecutingLoction
|
|
||||||
inc dword [edi]
|
|
||||||
mov ebx, [edi]
|
|
||||||
|
|
||||||
ProgramStack:
|
|
||||||
mov edi, esi
|
|
||||||
add edi, StackSizeLocation
|
|
||||||
mov eax, [edi]
|
|
||||||
mov edi, esi
|
|
||||||
add edi, StackStartAddressLocation
|
|
||||||
add eax, [edi]
|
|
||||||
mov esp, eax
|
|
||||||
mov [edi], eax
|
|
||||||
|
|
||||||
Releaselock:
|
|
||||||
mov eax, VacantFlag
|
|
||||||
mov edi, esi
|
|
||||||
add edi, LockLocation
|
|
||||||
xchg [edi], eax
|
|
||||||
|
|
||||||
CProcedureInvoke:
|
|
||||||
push ebp ; push BIST data at top of AP stack
|
|
||||||
xor ebp, ebp ; clear ebp for call stack trace
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
|
|
||||||
mov eax, ASM_PFX(InitializeFloatingPointUnits)
|
|
||||||
call eax ; Call assembly function to initialize FPU per UEFI spec
|
|
||||||
|
|
||||||
push ebx ; Push NumApsExecuting
|
|
||||||
mov eax, esi
|
|
||||||
add eax, LockLocation
|
|
||||||
push eax ; push address of exchange info data buffer
|
|
||||||
|
|
||||||
mov edi, esi
|
|
||||||
add edi, ApProcedureLocation
|
|
||||||
mov eax, [edi]
|
|
||||||
|
|
||||||
call eax ; invoke C function
|
|
||||||
|
|
||||||
jmp $ ; never reach here
|
|
||||||
RendezvousFunnelProcEnd:
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
; AsmGetAddressMap (&AddressMap);
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
global ASM_PFX(AsmGetAddressMap)
|
|
||||||
ASM_PFX(AsmGetAddressMap):
|
|
||||||
pushad
|
|
||||||
mov ebp,esp
|
|
||||||
|
|
||||||
mov ebx, [ebp + 24h]
|
|
||||||
mov dword [ebx], RendezvousFunnelProcStart
|
|
||||||
mov dword [ebx + 4h], Flat32Start - RendezvousFunnelProcStart
|
|
||||||
mov dword [ebx + 8h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
|
|
||||||
|
|
||||||
popad
|
|
||||||
ret
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
|
|
||||||
;about to become an AP. It switches it'stack with the current AP.
|
|
||||||
;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
global ASM_PFX(AsmExchangeRole)
|
|
||||||
ASM_PFX(AsmExchangeRole):
|
|
||||||
; DO NOT call other functions in this function, since 2 CPU may use 1 stack
|
|
||||||
; at the same time. If 1 CPU try to call a function, stack will be corrupted.
|
|
||||||
pushad
|
|
||||||
mov ebp,esp
|
|
||||||
|
|
||||||
; esi contains MyInfo pointer
|
|
||||||
mov esi, [ebp + 24h]
|
|
||||||
|
|
||||||
; edi contains OthersInfo pointer
|
|
||||||
mov edi, [ebp + 28h]
|
|
||||||
|
|
||||||
;Store EFLAGS, GDTR and IDTR register to stack
|
|
||||||
pushfd
|
|
||||||
mov eax, cr4
|
|
||||||
push eax ; push cr4 firstly
|
|
||||||
mov eax, cr0
|
|
||||||
push eax
|
|
||||||
|
|
||||||
sgdt [esi + 8]
|
|
||||||
sidt [esi + 14]
|
|
||||||
|
|
||||||
; Store the its StackPointer
|
|
||||||
mov [esi + 4],esp
|
|
||||||
|
|
||||||
; update its switch state to STORED
|
|
||||||
mov byte [esi], CPU_SWITCH_STATE_STORED
|
|
||||||
|
|
||||||
WaitForOtherStored:
|
|
||||||
; wait until the other CPU finish storing its state
|
|
||||||
cmp byte [edi], CPU_SWITCH_STATE_STORED
|
|
||||||
jz OtherStored
|
|
||||||
pause
|
|
||||||
jmp WaitForOtherStored
|
|
||||||
|
|
||||||
OtherStored:
|
|
||||||
; Since another CPU already stored its state, load them
|
|
||||||
; load GDTR value
|
|
||||||
lgdt [edi + 8]
|
|
||||||
|
|
||||||
; load IDTR value
|
|
||||||
lidt [edi + 14]
|
|
||||||
|
|
||||||
; load its future StackPointer
|
|
||||||
mov esp, [edi + 4]
|
|
||||||
|
|
||||||
; update the other CPU's switch state to LOADED
|
|
||||||
mov byte [edi], CPU_SWITCH_STATE_LOADED
|
|
||||||
|
|
||||||
WaitForOtherLoaded:
|
|
||||||
; wait until the other CPU finish loading new state,
|
|
||||||
; otherwise the data in stack may corrupt
|
|
||||||
cmp byte [esi], CPU_SWITCH_STATE_LOADED
|
|
||||||
jz OtherLoaded
|
|
||||||
pause
|
|
||||||
jmp WaitForOtherLoaded
|
|
||||||
|
|
||||||
OtherLoaded:
|
|
||||||
; since the other CPU already get the data it want, leave this procedure
|
|
||||||
pop eax
|
|
||||||
mov cr0, eax
|
|
||||||
pop eax
|
|
||||||
mov cr4, eax
|
|
||||||
popfd
|
|
||||||
|
|
||||||
popad
|
|
||||||
ret
|
|
@ -1,213 +0,0 @@
|
|||||||
/** @file
|
|
||||||
Implementation of loading microcode on processors.
|
|
||||||
|
|
||||||
Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
||||||
This program and the accompanying materials
|
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
|
||||||
http://opensource.org/licenses/bsd-license.php
|
|
||||||
|
|
||||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include "CpuMpPei.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get microcode update signature of currently loaded microcode update.
|
|
||||||
|
|
||||||
@return Microcode signature.
|
|
||||||
|
|
||||||
**/
|
|
||||||
UINT32
|
|
||||||
GetCurrentMicrocodeSignature (
|
|
||||||
VOID
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT64 Signature;
|
|
||||||
|
|
||||||
AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
|
|
||||||
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
|
|
||||||
Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);
|
|
||||||
return (UINT32) RShiftU64 (Signature, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Detect whether specified processor can find matching microcode patch and load it.
|
|
||||||
|
|
||||||
@param PeiCpuMpData Pointer to PEI CPU MP Data
|
|
||||||
**/
|
|
||||||
VOID
|
|
||||||
MicrocodeDetect (
|
|
||||||
IN PEI_CPU_MP_DATA *PeiCpuMpData
|
|
||||||
)
|
|
||||||
{
|
|
||||||
UINT64 MicrocodePatchAddress;
|
|
||||||
UINT64 MicrocodePatchRegionSize;
|
|
||||||
UINT32 ExtendedTableLength;
|
|
||||||
UINT32 ExtendedTableCount;
|
|
||||||
EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
|
|
||||||
EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
|
|
||||||
EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
|
|
||||||
UINTN MicrocodeEnd;
|
|
||||||
UINTN Index;
|
|
||||||
UINT8 PlatformId;
|
|
||||||
UINT32 RegEax;
|
|
||||||
UINT32 CurrentRevision;
|
|
||||||
UINT32 LatestRevision;
|
|
||||||
UINTN TotalSize;
|
|
||||||
UINT32 CheckSum32;
|
|
||||||
BOOLEAN CorrectMicrocode;
|
|
||||||
MICROCODE_INFO MicrocodeInfo;
|
|
||||||
|
|
||||||
ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));
|
|
||||||
MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
|
|
||||||
MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
|
|
||||||
if (MicrocodePatchRegionSize == 0) {
|
|
||||||
//
|
|
||||||
// There is no microcode patches
|
|
||||||
//
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentRevision = GetCurrentMicrocodeSignature ();
|
|
||||||
if (CurrentRevision != 0) {
|
|
||||||
//
|
|
||||||
// Skip loading microcode if it has been loaded successfully
|
|
||||||
//
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtendedTableLength = 0;
|
|
||||||
//
|
|
||||||
// Here data of CPUID leafs have not been collected into context buffer, so
|
|
||||||
// GetProcessorCpuid() cannot be used here to retrieve CPUID data.
|
|
||||||
//
|
|
||||||
AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
//
|
|
||||||
// The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
|
|
||||||
//
|
|
||||||
PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);
|
|
||||||
|
|
||||||
LatestRevision = 0;
|
|
||||||
MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);
|
|
||||||
MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
|
|
||||||
do {
|
|
||||||
//
|
|
||||||
// Check if the microcode is for the Cpu and the version is newer
|
|
||||||
// and the update can be processed on the platform
|
|
||||||
//
|
|
||||||
CorrectMicrocode = FALSE;
|
|
||||||
if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
|
|
||||||
//
|
|
||||||
// It is the microcode header. It is not the padding data between microcode patches
|
|
||||||
// because the padding data should not include 0x00000001 and it should be the repeated
|
|
||||||
// byte format (like 0xXYXYXYXY....).
|
|
||||||
//
|
|
||||||
if (MicrocodeEntryPoint->ProcessorId == RegEax &&
|
|
||||||
MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
|
|
||||||
(MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
|
|
||||||
) {
|
|
||||||
if (MicrocodeEntryPoint->DataSize == 0) {
|
|
||||||
CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);
|
|
||||||
} else {
|
|
||||||
CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));
|
|
||||||
}
|
|
||||||
if (CheckSum32 == 0) {
|
|
||||||
CorrectMicrocode = TRUE;
|
|
||||||
}
|
|
||||||
} else if ((MicrocodeEntryPoint->DataSize != 0) &&
|
|
||||||
(MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
|
|
||||||
ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
|
|
||||||
if (ExtendedTableLength != 0) {
|
|
||||||
//
|
|
||||||
// Extended Table exist, check if the CPU in support list
|
|
||||||
//
|
|
||||||
ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
|
|
||||||
//
|
|
||||||
// Calculate Extended Checksum
|
|
||||||
//
|
|
||||||
if ((ExtendedTableLength % 4) == 0) {
|
|
||||||
CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
|
|
||||||
if (CheckSum32 == 0) {
|
|
||||||
//
|
|
||||||
// Checksum correct
|
|
||||||
//
|
|
||||||
ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
|
|
||||||
ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
|
|
||||||
for (Index = 0; Index < ExtendedTableCount; Index ++) {
|
|
||||||
CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));
|
|
||||||
if (CheckSum32 == 0) {
|
|
||||||
//
|
|
||||||
// Verify Header
|
|
||||||
//
|
|
||||||
if ((ExtendedTable->ProcessorSignature == RegEax) &&
|
|
||||||
(ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
|
|
||||||
//
|
|
||||||
// Find one
|
|
||||||
//
|
|
||||||
CorrectMicrocode = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExtendedTable ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//
|
|
||||||
// It is the padding data between the microcode patches for microcode patches alignment.
|
|
||||||
// Because the microcode patch is the multiple of 1-KByte, the padding data should not
|
|
||||||
// exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
|
|
||||||
// alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
|
|
||||||
// find the next possible microcode patch header.
|
|
||||||
//
|
|
||||||
MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// Get the next patch.
|
|
||||||
//
|
|
||||||
if (MicrocodeEntryPoint->DataSize == 0) {
|
|
||||||
TotalSize = 2048;
|
|
||||||
} else {
|
|
||||||
TotalSize = MicrocodeEntryPoint->TotalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (CorrectMicrocode) {
|
|
||||||
LatestRevision = MicrocodeEntryPoint->UpdateRevision;
|
|
||||||
MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));
|
|
||||||
MicrocodeInfo.MicrocodeSize = TotalSize;
|
|
||||||
MicrocodeInfo.ProcessorId = RegEax;
|
|
||||||
}
|
|
||||||
|
|
||||||
MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
|
|
||||||
} while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
|
|
||||||
|
|
||||||
if (LatestRevision > CurrentRevision) {
|
|
||||||
//
|
|
||||||
// BIOS only authenticate updates that contain a numerically larger revision
|
|
||||||
// than the currently loaded revision, where Current Signature < New Update
|
|
||||||
// Revision. A processor with no loaded update is considered to have a
|
|
||||||
// revision equal to zero.
|
|
||||||
//
|
|
||||||
AsmWriteMsr64 (
|
|
||||||
EFI_MSR_IA32_BIOS_UPDT_TRIG,
|
|
||||||
(UINT64) (UINTN) MicrocodeInfo.MicrocodeData
|
|
||||||
);
|
|
||||||
//
|
|
||||||
// Get and check new microcode signature
|
|
||||||
//
|
|
||||||
CurrentRevision = GetCurrentMicrocodeSignature ();
|
|
||||||
if (CurrentRevision != LatestRevision) {
|
|
||||||
AcquireSpinLock(&PeiCpuMpData->MpLock);
|
|
||||||
DEBUG ((EFI_D_ERROR, "Updated microcode signature [0x%08x] does not match \
|
|
||||||
loaded microcode signature [0x%08x]\n", CurrentRevision, LatestRevision));
|
|
||||||
ReleaseSpinLock(&PeiCpuMpData->MpLock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/** @file
|
|
||||||
Definitions for loading microcode on processors.
|
|
||||||
|
|
||||||
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
|
||||||
This program and the accompanying materials
|
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
|
||||||
http://opensource.org/licenses/bsd-license.php
|
|
||||||
|
|
||||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef _CPU_MICROCODE_H_
|
|
||||||
#define _CPU_MICROCODE_H_
|
|
||||||
|
|
||||||
#define EFI_MSR_IA32_PLATFORM_ID 0x17
|
|
||||||
#define EFI_MSR_IA32_BIOS_UPDT_TRIG 0x79
|
|
||||||
#define EFI_MSR_IA32_BIOS_SIGN_ID 0x8b
|
|
||||||
|
|
||||||
#define MAX_MICROCODE_DESCRIPTOR_LENGTH 100
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
VOID *MicrocodeData;
|
|
||||||
UINTN MicrocodeSize;
|
|
||||||
UINT32 ProcessorId;
|
|
||||||
} MICROCODE_INFO;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Definition for IA32 microcode format
|
|
||||||
//
|
|
||||||
typedef struct {
|
|
||||||
UINT32 HeaderVersion;
|
|
||||||
UINT32 UpdateRevision;
|
|
||||||
UINT32 Date;
|
|
||||||
UINT32 ProcessorId;
|
|
||||||
UINT32 Checksum;
|
|
||||||
UINT32 LoaderRevision;
|
|
||||||
UINT32 ProcessorFlags;
|
|
||||||
UINT32 DataSize;
|
|
||||||
UINT32 TotalSize;
|
|
||||||
UINT8 Reserved[12];
|
|
||||||
} EFI_CPU_MICROCODE_HEADER;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
UINT32 ExtendedSignatureCount;
|
|
||||||
UINT32 ExtendedTableChecksum;
|
|
||||||
UINT8 Reserved[12];
|
|
||||||
} EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
UINT32 ProcessorSignature;
|
|
||||||
UINT32 ProcessorFlag;
|
|
||||||
UINT32 ProcessorChecksum;
|
|
||||||
} EFI_CPU_MICROCODE_EXTENDED_TABLE;
|
|
||||||
|
|
||||||
#endif
|
|
@ -34,137 +34,6 @@ EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get CPU Package/Core/Thread location information.
|
|
||||||
|
|
||||||
@param InitialApicId CPU APIC ID
|
|
||||||
@param Location Pointer to CPU location information
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
ExtractProcessorLocation (
|
|
||||||
IN UINT32 InitialApicId,
|
|
||||||
OUT EFI_CPU_PHYSICAL_LOCATION *Location
|
|
||||||
)
|
|
||||||
{
|
|
||||||
BOOLEAN TopologyLeafSupported;
|
|
||||||
UINTN ThreadBits;
|
|
||||||
UINTN CoreBits;
|
|
||||||
UINT32 RegEax;
|
|
||||||
UINT32 RegEbx;
|
|
||||||
UINT32 RegEcx;
|
|
||||||
UINT32 RegEdx;
|
|
||||||
UINT32 MaxCpuIdIndex;
|
|
||||||
UINT32 SubIndex;
|
|
||||||
UINTN LevelType;
|
|
||||||
UINT32 MaxLogicProcessorsPerPackage;
|
|
||||||
UINT32 MaxCoresPerPackage;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Check if the processor is capable of supporting more than one logical processor.
|
|
||||||
//
|
|
||||||
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
|
|
||||||
if ((RegEdx & BIT28) == 0) {
|
|
||||||
Location->Thread = 0;
|
|
||||||
Location->Core = 0;
|
|
||||||
Location->Package = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadBits = 0;
|
|
||||||
CoreBits = 0;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Assume three-level mapping of APIC ID: Package:Core:SMT.
|
|
||||||
//
|
|
||||||
|
|
||||||
TopologyLeafSupported = FALSE;
|
|
||||||
//
|
|
||||||
// Get the max index of basic CPUID
|
|
||||||
//
|
|
||||||
AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
//
|
|
||||||
// If the extended topology enumeration leaf is available, it
|
|
||||||
// is the preferred mechanism for enumerating topology.
|
|
||||||
//
|
|
||||||
if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
|
|
||||||
AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &RegEax, &RegEbx, &RegEcx, NULL);
|
|
||||||
//
|
|
||||||
// If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
|
|
||||||
// basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
|
|
||||||
// supported on that processor.
|
|
||||||
//
|
|
||||||
if (RegEbx != 0) {
|
|
||||||
TopologyLeafSupported = TRUE;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
|
|
||||||
// the SMT sub-field of x2APIC ID.
|
|
||||||
//
|
|
||||||
LevelType = (RegEcx >> 8) & 0xff;
|
|
||||||
ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
|
|
||||||
ThreadBits = RegEax & 0x1f;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Software must not assume any "level type" encoding
|
|
||||||
// value to be related to any sub-leaf index, except sub-leaf 0.
|
|
||||||
//
|
|
||||||
SubIndex = 1;
|
|
||||||
do {
|
|
||||||
AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, SubIndex, &RegEax, NULL, &RegEcx, NULL);
|
|
||||||
LevelType = (RegEcx >> 8) & 0xff;
|
|
||||||
if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
|
|
||||||
CoreBits = (RegEax & 0x1f) - ThreadBits;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
SubIndex++;
|
|
||||||
} while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TopologyLeafSupported) {
|
|
||||||
AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
|
|
||||||
MaxLogicProcessorsPerPackage = (RegEbx >> 16) & 0xff;
|
|
||||||
if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
|
|
||||||
AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL);
|
|
||||||
MaxCoresPerPackage = (RegEax >> 26) + 1;
|
|
||||||
} else {
|
|
||||||
//
|
|
||||||
// Must be a single-core processor.
|
|
||||||
//
|
|
||||||
MaxCoresPerPackage = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
|
|
||||||
CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Location->Thread = InitialApicId & ~((-1) << ThreadBits);
|
|
||||||
Location->Core = (InitialApicId >> ThreadBits) & ~((-1) << CoreBits);
|
|
||||||
Location->Package = (InitialApicId >> (ThreadBits + CoreBits));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Worker function for SwitchBSP().
|
|
||||||
|
|
||||||
Worker function for SwitchBSP(), assigned to the AP which is intended to become BSP.
|
|
||||||
|
|
||||||
@param Buffer Pointer to CPU MP Data
|
|
||||||
**/
|
|
||||||
STATIC
|
|
||||||
VOID
|
|
||||||
EFIAPI
|
|
||||||
FutureBSPProc (
|
|
||||||
IN VOID *Buffer
|
|
||||||
)
|
|
||||||
{
|
|
||||||
PEI_CPU_MP_DATA *DataInHob;
|
|
||||||
|
|
||||||
DataInHob = (PEI_CPU_MP_DATA *) Buffer;
|
|
||||||
AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This service retrieves the number of logical processor in the platform
|
This service retrieves the number of logical processor in the platform
|
||||||
and the number of those logical processors that are enabled on this boot.
|
and the number of those logical processors that are enabled on this boot.
|
||||||
|
@ -17,29 +17,6 @@
|
|||||||
|
|
||||||
#include "CpuMpPei.h"
|
#include "CpuMpPei.h"
|
||||||
|
|
||||||
//
|
|
||||||
// The MP data for switch BSP
|
|
||||||
//
|
|
||||||
#define CPU_SWITCH_STATE_IDLE 0
|
|
||||||
#define CPU_SWITCH_STATE_STORED 1
|
|
||||||
#define CPU_SWITCH_STATE_LOADED 2
|
|
||||||
|
|
||||||
#define CPU_CHECK_AP_INTERVAL 0x100 // 100 microseconds
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function is called by both the BSP and the AP which is to become the BSP to
|
|
||||||
Exchange execution context including stack between them. After return from this
|
|
||||||
function, the BSP becomes AP and the AP becomes the BSP.
|
|
||||||
|
|
||||||
@param MyInfo Pointer to buffer holding the exchanging information for the executing processor.
|
|
||||||
@param OthersInfo Pointer to buffer holding the exchanging information for the peer.
|
|
||||||
**/
|
|
||||||
VOID
|
|
||||||
EFIAPI
|
|
||||||
AsmExchangeRole (
|
|
||||||
IN CPU_EXCHANGE_ROLE_INFO *MyInfo,
|
|
||||||
IN CPU_EXCHANGE_ROLE_INFO *OthersInfo
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This service retrieves the number of logical processor in the platform
|
This service retrieves the number of logical processor in the platform
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
;------------------------------------------------------------------------------ ;
|
|
||||||
; Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
||||||
; This program and the accompanying materials
|
|
||||||
; are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
; which accompanies this distribution. The full text of the license may be found at
|
|
||||||
; http://opensource.org/licenses/bsd-license.php.
|
|
||||||
;
|
|
||||||
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
;
|
|
||||||
; Module Name:
|
|
||||||
;
|
|
||||||
; MpEqu.inc
|
|
||||||
;
|
|
||||||
; Abstract:
|
|
||||||
;
|
|
||||||
; This is the equates file for Multiple Processor support
|
|
||||||
;
|
|
||||||
;-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
VacantFlag equ 00h
|
|
||||||
NotVacantFlag equ 0ffh
|
|
||||||
|
|
||||||
CPU_SWITCH_STATE_IDLE equ 0
|
|
||||||
CPU_SWITCH_STATE_STORED equ 1
|
|
||||||
CPU_SWITCH_STATE_LOADED equ 2
|
|
||||||
|
|
||||||
LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
|
|
||||||
StackStartAddressLocation equ LockLocation + 08h
|
|
||||||
StackSizeLocation equ LockLocation + 10h
|
|
||||||
ApProcedureLocation equ LockLocation + 18h
|
|
||||||
GdtrLocation equ LockLocation + 20h
|
|
||||||
IdtrLocation equ LockLocation + 2Ah
|
|
||||||
BufferStartLocation equ LockLocation + 34h
|
|
||||||
ModeOffsetLocation equ LockLocation + 3Ch
|
|
||||||
NumApsExecutingLoction equ LockLocation + 44h
|
|
||||||
CodeSegmentLocation equ LockLocation + 4Ch
|
|
||||||
DataSegmentLocation equ LockLocation + 54h
|
|
||||||
Cr3Location equ LockLocation + 5Ch
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------
|
|
@ -1,290 +0,0 @@
|
|||||||
;------------------------------------------------------------------------------ ;
|
|
||||||
; Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
||||||
; This program and the accompanying materials
|
|
||||||
; are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
; which accompanies this distribution. The full text of the license may be found at
|
|
||||||
; http://opensource.org/licenses/bsd-license.php.
|
|
||||||
;
|
|
||||||
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
;
|
|
||||||
; Module Name:
|
|
||||||
;
|
|
||||||
; MpFuncs32.asm
|
|
||||||
;
|
|
||||||
; Abstract:
|
|
||||||
;
|
|
||||||
; This is the assembly code for MP support
|
|
||||||
;
|
|
||||||
;-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
include MpEqu.inc
|
|
||||||
extern InitializeFloatingPointUnits:PROC
|
|
||||||
|
|
||||||
.code
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
|
|
||||||
;procedure serializes all the AP processors through an Init sequence. It must be
|
|
||||||
;noted that APs arrive here very raw...ie: real mode, no stack.
|
|
||||||
;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
|
|
||||||
;IS IN MACHINE CODE.
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
RendezvousFunnelProc PROC PUBLIC
|
|
||||||
RendezvousFunnelProcStart::
|
|
||||||
; At this point CS = 0x(vv00) and ip= 0x0.
|
|
||||||
; Save BIST information to ebp firstly
|
|
||||||
db 66h, 08bh, 0e8h ; mov ebp, eax ; save BIST information
|
|
||||||
|
|
||||||
db 8ch,0c8h ; mov ax, cs
|
|
||||||
db 8eh,0d8h ; mov ds, ax
|
|
||||||
db 8eh,0c0h ; mov es, ax
|
|
||||||
db 8eh,0d0h ; mov ss, ax
|
|
||||||
db 33h,0c0h ; xor ax, ax
|
|
||||||
db 8eh,0e0h ; mov fs, ax
|
|
||||||
db 8eh,0e8h ; mov gs, ax
|
|
||||||
|
|
||||||
db 0BEh ; opcode of mov si, mem16
|
|
||||||
dw BufferStartLocation ; mov si, BufferStartLocation
|
|
||||||
db 66h, 8Bh, 1Ch ; mov ebx, dword ptr [si]
|
|
||||||
|
|
||||||
db 0BFh ; opcode of mov di, mem16
|
|
||||||
dw ModeOffsetLocation ; mov di, ModeOffsetLocation
|
|
||||||
db 66h, 8Bh, 05h ; mov eax, [di]
|
|
||||||
db 0BFh ; opcode of mov di, mem16
|
|
||||||
dw CodeSegmentLocation ; mov di, CodeSegmentLocation
|
|
||||||
db 66h, 8Bh, 15h ; mov edx, [di]
|
|
||||||
db 89h, 0C7h ; mov di, ax
|
|
||||||
db 83h, 0EFh, 02h ; sub di, 02h
|
|
||||||
db 89h, 15h ; mov [di], dx ; Patch long mode CS
|
|
||||||
db 83h, 0EFh, 04h ; sub di, 04h
|
|
||||||
db 66h, 01h, 0D8h ; add eax, ebx
|
|
||||||
db 66h, 89h, 05h ; mov [di], eax ; Patch address
|
|
||||||
|
|
||||||
db 0BEh ; opcode of mov si, mem16
|
|
||||||
dw GdtrLocation ; mov si, GdtrLocation
|
|
||||||
db 66h ; db 66h
|
|
||||||
db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
|
|
||||||
|
|
||||||
db 0BEh
|
|
||||||
dw IdtrLocation ; mov si, IdtrLocation
|
|
||||||
db 66h ; db 66h
|
|
||||||
db 2Eh,0Fh, 01h, 1Ch ; lidt fword ptr cs:[si]
|
|
||||||
|
|
||||||
db 0BFh ; opcode of mov di, mem16
|
|
||||||
dw DataSegmentLocation ; mov di, DataSegmentLocation
|
|
||||||
db 66h, 8Bh, 3Dh ; mov edi, [di] ; Save long mode DS in edi
|
|
||||||
|
|
||||||
db 0BEh
|
|
||||||
dw Cr3Location ; mov si, Cr3Location
|
|
||||||
db 66h, 8Bh, 0Ch ; mov ecx, dword ptr [si] ; ECX is keeping the value of CR3
|
|
||||||
|
|
||||||
db 31h, 0C0h ; xor ax, ax
|
|
||||||
db 8Eh, 0D8h ; mov ds, ax ; Clear data segment
|
|
||||||
|
|
||||||
db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Get control register 0
|
|
||||||
db 66h, 83h, 0C8h, 03h ; or eax, 000000003h ; Set PE bit (bit #0) & MP
|
|
||||||
db 0Fh, 22h, 0C0h ; mov cr0, eax
|
|
||||||
|
|
||||||
db 0Fh, 20h, 0E0h ; mov eax, cr4
|
|
||||||
db 66h, 0Fh, 0BAh, 0E8h, 05h ; bts eax, 5
|
|
||||||
db 0Fh, 22h, 0E0h ; mov cr4, eax
|
|
||||||
|
|
||||||
db 0Fh, 22h, 0D9h ; mov cr3, ecx
|
|
||||||
|
|
||||||
db 66h, 0B9h
|
|
||||||
dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number.
|
|
||||||
db 0Fh, 32h ; rdmsr ; Read EFER.
|
|
||||||
db 66h, 0Fh, 0BAh, 0E8h, 08h; bts eax, 8 ; Set LME=1.
|
|
||||||
db 0Fh, 30h ; wrmsr ; Write EFER.
|
|
||||||
|
|
||||||
db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0.
|
|
||||||
db 66h, 0Fh, 0BAh, 0E8h, 1Fh; bts eax, 31 ; Set PG=1.
|
|
||||||
db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0.
|
|
||||||
|
|
||||||
LONG_JUMP:
|
|
||||||
db 66h, 0EAh ; far jump
|
|
||||||
dd 0h ; 32-bit offset
|
|
||||||
dw 0h ; 16-bit selector
|
|
||||||
|
|
||||||
LongModeStart::
|
|
||||||
mov eax, edi
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov ss, ax
|
|
||||||
|
|
||||||
mov esi, ebx
|
|
||||||
mov edi, esi
|
|
||||||
add edi, LockLocation
|
|
||||||
mov rax, NotVacantFlag
|
|
||||||
|
|
||||||
TestLock:
|
|
||||||
xchg qword ptr [edi], rax
|
|
||||||
cmp rax, NotVacantFlag
|
|
||||||
jz TestLock
|
|
||||||
|
|
||||||
mov edi, esi
|
|
||||||
add edi, NumApsExecutingLoction
|
|
||||||
inc dword ptr [edi]
|
|
||||||
mov ebx, dword ptr [edi]
|
|
||||||
|
|
||||||
ProgramStack:
|
|
||||||
mov edi, esi
|
|
||||||
add edi, StackSizeLocation
|
|
||||||
mov rax, qword ptr [edi]
|
|
||||||
mov edi, esi
|
|
||||||
add edi, StackStartAddressLocation
|
|
||||||
add rax, qword ptr [edi]
|
|
||||||
mov rsp, rax
|
|
||||||
mov qword ptr [edi], rax
|
|
||||||
|
|
||||||
Releaselock:
|
|
||||||
mov rax, VacantFlag
|
|
||||||
mov edi, esi
|
|
||||||
add edi, LockLocation
|
|
||||||
xchg qword ptr [edi], rax
|
|
||||||
|
|
||||||
CProcedureInvoke:
|
|
||||||
push rbp ; push BIST data
|
|
||||||
xor rbp, rbp ; clear ebp for call stack trace
|
|
||||||
push rbp
|
|
||||||
mov rbp, rsp
|
|
||||||
|
|
||||||
mov rax, InitializeFloatingPointUnits
|
|
||||||
sub rsp, 20h
|
|
||||||
call rax ; Call assembly function to initialize FPU per UEFI spec
|
|
||||||
add rsp, 20h
|
|
||||||
|
|
||||||
mov edx, ebx ; edx is NumApsExecuting
|
|
||||||
mov ecx, esi
|
|
||||||
add ecx, LockLocation ; rcx is address of exchange info data buffer
|
|
||||||
|
|
||||||
mov edi, esi
|
|
||||||
add edi, ApProcedureLocation
|
|
||||||
mov rax, qword ptr [edi]
|
|
||||||
|
|
||||||
sub rsp, 20h
|
|
||||||
call rax ; invoke C function
|
|
||||||
add rsp, 20h
|
|
||||||
jmp $
|
|
||||||
|
|
||||||
RendezvousFunnelProc ENDP
|
|
||||||
RendezvousFunnelProcEnd::
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
; AsmGetAddressMap (&AddressMap);
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
AsmGetAddressMap PROC
|
|
||||||
mov rax, offset RendezvousFunnelProcStart
|
|
||||||
mov qword ptr [rcx], rax
|
|
||||||
mov qword ptr [rcx + 8h], LongModeStart - RendezvousFunnelProcStart
|
|
||||||
mov qword ptr [rcx + 10h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
|
|
||||||
ret
|
|
||||||
AsmGetAddressMap ENDP
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
|
|
||||||
;about to become an AP. It switches it'stack with the current AP.
|
|
||||||
;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
AsmExchangeRole PROC
|
|
||||||
; DO NOT call other functions in this function, since 2 CPU may use 1 stack
|
|
||||||
; at the same time. If 1 CPU try to call a function, stack will be corrupted.
|
|
||||||
|
|
||||||
push rax
|
|
||||||
push rbx
|
|
||||||
push rcx
|
|
||||||
push rdx
|
|
||||||
push rsi
|
|
||||||
push rdi
|
|
||||||
push rbp
|
|
||||||
push r8
|
|
||||||
push r9
|
|
||||||
push r10
|
|
||||||
push r11
|
|
||||||
push r12
|
|
||||||
push r13
|
|
||||||
push r14
|
|
||||||
push r15
|
|
||||||
|
|
||||||
mov rax, cr0
|
|
||||||
push rax
|
|
||||||
|
|
||||||
mov rax, cr4
|
|
||||||
push rax
|
|
||||||
|
|
||||||
; rsi contains MyInfo pointer
|
|
||||||
mov rsi, rcx
|
|
||||||
|
|
||||||
; rdi contains OthersInfo pointer
|
|
||||||
mov rdi, rdx
|
|
||||||
|
|
||||||
;Store EFLAGS, GDTR and IDTR regiter to stack
|
|
||||||
pushfq
|
|
||||||
sgdt fword ptr [rsi + 16]
|
|
||||||
sidt fword ptr [rsi + 26]
|
|
||||||
|
|
||||||
; Store the its StackPointer
|
|
||||||
mov qword ptr [rsi + 8], rsp
|
|
||||||
|
|
||||||
; update its switch state to STORED
|
|
||||||
mov byte ptr [rsi], CPU_SWITCH_STATE_STORED
|
|
||||||
|
|
||||||
WaitForOtherStored:
|
|
||||||
; wait until the other CPU finish storing its state
|
|
||||||
cmp byte ptr [rdi], CPU_SWITCH_STATE_STORED
|
|
||||||
jz OtherStored
|
|
||||||
pause
|
|
||||||
jmp WaitForOtherStored
|
|
||||||
|
|
||||||
OtherStored:
|
|
||||||
; Since another CPU already stored its state, load them
|
|
||||||
; load GDTR value
|
|
||||||
lgdt fword ptr [rdi + 16]
|
|
||||||
|
|
||||||
; load IDTR value
|
|
||||||
lidt fword ptr [rdi + 26]
|
|
||||||
|
|
||||||
; load its future StackPointer
|
|
||||||
mov rsp, qword ptr [rdi + 8]
|
|
||||||
|
|
||||||
; update the other CPU's switch state to LOADED
|
|
||||||
mov byte ptr [rdi], CPU_SWITCH_STATE_LOADED
|
|
||||||
|
|
||||||
WaitForOtherLoaded:
|
|
||||||
; wait until the other CPU finish loading new state,
|
|
||||||
; otherwise the data in stack may corrupt
|
|
||||||
cmp byte ptr [rsi], CPU_SWITCH_STATE_LOADED
|
|
||||||
jz OtherLoaded
|
|
||||||
pause
|
|
||||||
jmp WaitForOtherLoaded
|
|
||||||
|
|
||||||
OtherLoaded:
|
|
||||||
; since the other CPU already get the data it want, leave this procedure
|
|
||||||
popfq
|
|
||||||
|
|
||||||
pop rax
|
|
||||||
mov cr4, rax
|
|
||||||
|
|
||||||
pop rax
|
|
||||||
mov cr0, rax
|
|
||||||
|
|
||||||
pop r15
|
|
||||||
pop r14
|
|
||||||
pop r13
|
|
||||||
pop r12
|
|
||||||
pop r11
|
|
||||||
pop r10
|
|
||||||
pop r9
|
|
||||||
pop r8
|
|
||||||
pop rbp
|
|
||||||
pop rdi
|
|
||||||
pop rsi
|
|
||||||
pop rdx
|
|
||||||
pop rcx
|
|
||||||
pop rbx
|
|
||||||
pop rax
|
|
||||||
|
|
||||||
ret
|
|
||||||
AsmExchangeRole ENDP
|
|
||||||
|
|
||||||
END
|
|
@ -1,281 +0,0 @@
|
|||||||
;------------------------------------------------------------------------------ ;
|
|
||||||
; Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
||||||
; This program and the accompanying materials
|
|
||||||
; are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
; which accompanies this distribution. The full text of the license may be found at
|
|
||||||
; http://opensource.org/licenses/bsd-license.php.
|
|
||||||
;
|
|
||||||
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
;
|
|
||||||
; Module Name:
|
|
||||||
;
|
|
||||||
; MpFuncs.nasm
|
|
||||||
;
|
|
||||||
; Abstract:
|
|
||||||
;
|
|
||||||
; This is the assembly code for MP support
|
|
||||||
;
|
|
||||||
;-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
%include "MpEqu.inc"
|
|
||||||
extern ASM_PFX(InitializeFloatingPointUnits)
|
|
||||||
|
|
||||||
DEFAULT REL
|
|
||||||
|
|
||||||
SECTION .text
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
|
|
||||||
;procedure serializes all the AP processors through an Init sequence. It must be
|
|
||||||
;noted that APs arrive here very raw...ie: real mode, no stack.
|
|
||||||
;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
|
|
||||||
;IS IN MACHINE CODE.
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
global ASM_PFX(RendezvousFunnelProc)
|
|
||||||
ASM_PFX(RendezvousFunnelProc):
|
|
||||||
RendezvousFunnelProcStart:
|
|
||||||
; At this point CS = 0x(vv00) and ip= 0x0.
|
|
||||||
; Save BIST information to ebp firstly
|
|
||||||
|
|
||||||
BITS 16
|
|
||||||
mov ebp, eax ; Save BIST information
|
|
||||||
|
|
||||||
mov ax, cs
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov ss, ax
|
|
||||||
xor ax, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
|
|
||||||
mov si, BufferStartLocation
|
|
||||||
mov ebx, [si]
|
|
||||||
|
|
||||||
mov di, ModeOffsetLocation
|
|
||||||
mov eax, [di]
|
|
||||||
mov di, CodeSegmentLocation
|
|
||||||
mov edx, [di]
|
|
||||||
mov di, ax
|
|
||||||
sub di, 02h
|
|
||||||
mov [di],dx ; Patch long mode CS
|
|
||||||
sub di, 04h
|
|
||||||
add eax, ebx
|
|
||||||
mov [di],eax ; Patch address
|
|
||||||
|
|
||||||
mov si, GdtrLocation
|
|
||||||
o32 lgdt [cs:si]
|
|
||||||
|
|
||||||
mov si, IdtrLocation
|
|
||||||
o32 lidt [cs:si]
|
|
||||||
|
|
||||||
|
|
||||||
mov di, DataSegmentLocation
|
|
||||||
mov edi, [di] ; Save long mode DS in edi
|
|
||||||
|
|
||||||
mov si, Cr3Location ; Save CR3 in ecx
|
|
||||||
mov ecx, [si]
|
|
||||||
|
|
||||||
xor ax, ax
|
|
||||||
mov ds, ax ; Clear data segment
|
|
||||||
|
|
||||||
mov eax, cr0 ; Get control register 0
|
|
||||||
or eax, 000000003h ; Set PE bit (bit #0) & MP
|
|
||||||
mov cr0, eax
|
|
||||||
|
|
||||||
mov eax, cr4
|
|
||||||
bts eax, 5
|
|
||||||
mov cr4, eax
|
|
||||||
|
|
||||||
mov cr3, ecx ; Load CR3
|
|
||||||
|
|
||||||
mov ecx, 0c0000080h ; EFER MSR number
|
|
||||||
rdmsr ; Read EFER
|
|
||||||
bts eax, 8 ; Set LME=1
|
|
||||||
wrmsr ; Write EFER
|
|
||||||
|
|
||||||
mov eax, cr0 ; Read CR0
|
|
||||||
bts eax, 31 ; Set PG=1
|
|
||||||
mov cr0, eax ; Write CR0
|
|
||||||
|
|
||||||
jmp 0:strict dword 0 ; far jump to long mode
|
|
||||||
BITS 64
|
|
||||||
LongModeStart:
|
|
||||||
mov eax, edi
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov ss, ax
|
|
||||||
|
|
||||||
mov esi, ebx
|
|
||||||
mov edi, esi
|
|
||||||
add edi, LockLocation
|
|
||||||
mov rax, NotVacantFlag
|
|
||||||
|
|
||||||
TestLock:
|
|
||||||
xchg qword [edi], rax
|
|
||||||
cmp rax, NotVacantFlag
|
|
||||||
jz TestLock
|
|
||||||
|
|
||||||
mov edi, esi
|
|
||||||
add edi, NumApsExecutingLoction
|
|
||||||
inc dword [edi]
|
|
||||||
mov ebx, [edi]
|
|
||||||
|
|
||||||
ProgramStack:
|
|
||||||
mov edi, esi
|
|
||||||
add edi, StackSizeLocation
|
|
||||||
mov rax, qword [edi]
|
|
||||||
mov edi, esi
|
|
||||||
add edi, StackStartAddressLocation
|
|
||||||
add rax, qword [edi]
|
|
||||||
mov rsp, rax
|
|
||||||
mov qword [edi], rax
|
|
||||||
|
|
||||||
Releaselock:
|
|
||||||
mov rax, VacantFlag
|
|
||||||
mov edi, esi
|
|
||||||
add edi, LockLocation
|
|
||||||
xchg qword [edi], rax
|
|
||||||
|
|
||||||
CProcedureInvoke:
|
|
||||||
push rbp ; push BIST data at top of AP stack
|
|
||||||
xor rbp, rbp ; clear ebp for call stack trace
|
|
||||||
push rbp
|
|
||||||
mov rbp, rsp
|
|
||||||
|
|
||||||
mov rax, ASM_PFX(InitializeFloatingPointUnits)
|
|
||||||
sub rsp, 20h
|
|
||||||
call rax ; Call assembly function to initialize FPU per UEFI spec
|
|
||||||
add rsp, 20h
|
|
||||||
|
|
||||||
mov edx, ebx ; edx is NumApsExecuting
|
|
||||||
mov ecx, esi
|
|
||||||
add ecx, LockLocation ; rcx is address of exchange info data buffer
|
|
||||||
|
|
||||||
mov edi, esi
|
|
||||||
add edi, ApProcedureLocation
|
|
||||||
mov rax, qword [edi]
|
|
||||||
|
|
||||||
sub rsp, 20h
|
|
||||||
call rax ; invoke C function
|
|
||||||
add rsp, 20h
|
|
||||||
jmp $
|
|
||||||
|
|
||||||
RendezvousFunnelProcEnd:
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
; AsmGetAddressMap (&AddressMap);
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
global ASM_PFX(AsmGetAddressMap)
|
|
||||||
ASM_PFX(AsmGetAddressMap):
|
|
||||||
mov rax, ASM_PFX(RendezvousFunnelProc)
|
|
||||||
mov qword [rcx], rax
|
|
||||||
mov qword [rcx + 8h], LongModeStart - RendezvousFunnelProcStart
|
|
||||||
mov qword [rcx + 10h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
|
|
||||||
ret
|
|
||||||
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
|
|
||||||
;about to become an AP. It switches it'stack with the current AP.
|
|
||||||
;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
|
|
||||||
;-------------------------------------------------------------------------------------
|
|
||||||
global ASM_PFX(AsmExchangeRole)
|
|
||||||
ASM_PFX(AsmExchangeRole):
|
|
||||||
; DO NOT call other functions in this function, since 2 CPU may use 1 stack
|
|
||||||
; at the same time. If 1 CPU try to call a function, stack will be corrupted.
|
|
||||||
|
|
||||||
push rax
|
|
||||||
push rbx
|
|
||||||
push rcx
|
|
||||||
push rdx
|
|
||||||
push rsi
|
|
||||||
push rdi
|
|
||||||
push rbp
|
|
||||||
push r8
|
|
||||||
push r9
|
|
||||||
push r10
|
|
||||||
push r11
|
|
||||||
push r12
|
|
||||||
push r13
|
|
||||||
push r14
|
|
||||||
push r15
|
|
||||||
|
|
||||||
mov rax, cr0
|
|
||||||
push rax
|
|
||||||
|
|
||||||
mov rax, cr4
|
|
||||||
push rax
|
|
||||||
|
|
||||||
; rsi contains MyInfo pointer
|
|
||||||
mov rsi, rcx
|
|
||||||
|
|
||||||
; rdi contains OthersInfo pointer
|
|
||||||
mov rdi, rdx
|
|
||||||
|
|
||||||
;Store EFLAGS, GDTR and IDTR regiter to stack
|
|
||||||
pushfq
|
|
||||||
sgdt [rsi + 16]
|
|
||||||
sidt [rsi + 26]
|
|
||||||
|
|
||||||
; Store the its StackPointer
|
|
||||||
mov [rsi + 8], rsp
|
|
||||||
|
|
||||||
; update its switch state to STORED
|
|
||||||
mov byte [rsi], CPU_SWITCH_STATE_STORED
|
|
||||||
|
|
||||||
WaitForOtherStored:
|
|
||||||
; wait until the other CPU finish storing its state
|
|
||||||
cmp byte [rdi], CPU_SWITCH_STATE_STORED
|
|
||||||
jz OtherStored
|
|
||||||
pause
|
|
||||||
jmp WaitForOtherStored
|
|
||||||
|
|
||||||
OtherStored:
|
|
||||||
; Since another CPU already stored its state, load them
|
|
||||||
; load GDTR value
|
|
||||||
lgdt [rdi + 16]
|
|
||||||
|
|
||||||
; load IDTR value
|
|
||||||
lidt [rdi + 26]
|
|
||||||
|
|
||||||
; load its future StackPointer
|
|
||||||
mov rsp, [rdi + 8]
|
|
||||||
|
|
||||||
; update the other CPU's switch state to LOADED
|
|
||||||
mov byte [rdi], CPU_SWITCH_STATE_LOADED
|
|
||||||
|
|
||||||
WaitForOtherLoaded:
|
|
||||||
; wait until the other CPU finish loading new state,
|
|
||||||
; otherwise the data in stack may corrupt
|
|
||||||
cmp byte [rsi], CPU_SWITCH_STATE_LOADED
|
|
||||||
jz OtherLoaded
|
|
||||||
pause
|
|
||||||
jmp WaitForOtherLoaded
|
|
||||||
|
|
||||||
OtherLoaded:
|
|
||||||
; since the other CPU already get the data it want, leave this procedure
|
|
||||||
popfq
|
|
||||||
|
|
||||||
pop rax
|
|
||||||
mov cr4, rax
|
|
||||||
|
|
||||||
pop rax
|
|
||||||
mov cr0, rax
|
|
||||||
|
|
||||||
pop r15
|
|
||||||
pop r14
|
|
||||||
pop r13
|
|
||||||
pop r12
|
|
||||||
pop r11
|
|
||||||
pop r10
|
|
||||||
pop r9
|
|
||||||
pop r8
|
|
||||||
pop rbp
|
|
||||||
pop rdi
|
|
||||||
pop rsi
|
|
||||||
pop rdx
|
|
||||||
pop rcx
|
|
||||||
pop rbx
|
|
||||||
pop rax
|
|
||||||
|
|
||||||
ret
|
|
Loading…
x
Reference in New Issue
Block a user