mirror of https://github.com/acidanthera/audk.git
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"
|
||||
|
||||
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.
|
||||
|
||||
|
|
|
@ -21,258 +21,20 @@
|
|||
#include <Ppi/SecPlatformInformation.h>
|
||||
#include <Ppi/SecPlatformInformation2.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/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/HobLib.h>
|
||||
#include <Library/LocalApicLib.h>
|
||||
#include <Library/MtrrLib.h>
|
||||
#include <Library/PcdLib.h>
|
||||
#include <Library/PeimEntryPoint.h>
|
||||
#include <Library/PeiServicesLib.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/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;
|
||||
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
|
@ -307,14 +69,4 @@ SecPlatformInformation2 (
|
|||
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
|
||||
|
|
|
@ -31,21 +31,9 @@
|
|||
CpuMpPei.h
|
||||
CpuMpPei.c
|
||||
CpuBist.c
|
||||
Microcode.h
|
||||
Microcode.c
|
||||
PeiMpServices.h
|
||||
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]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
@ -53,40 +41,23 @@
|
|||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
HobLib
|
||||
LocalApicLib
|
||||
MtrrLib
|
||||
PcdLib
|
||||
PeimEntryPoint
|
||||
PeiServicesLib
|
||||
ReportStatusCodeLib
|
||||
SynchronizationLib
|
||||
TimerLib
|
||||
UefiCpuLib
|
||||
CpuLib
|
||||
CpuExceptionHandlerLib
|
||||
MpInitLib
|
||||
|
||||
[Ppis]
|
||||
gEfiPeiMpServicesPpiGuid ## PRODUCES
|
||||
gEfiEndOfPeiSignalPpiGuid ## NOTIFY
|
||||
gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES
|
||||
## SOMETIMES_CONSUMES
|
||||
## SOMETIMES_PRODUCES
|
||||
gEfiSecPlatformInformation2PpiGuid
|
||||
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]
|
||||
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
|
||||
and the number of those logical processors that are enabled on this boot.
|
||||
|
|
|
@ -17,29 +17,6 @@
|
|||
|
||||
#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
|
||||
|
|
|
@ -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…
Reference in New Issue