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:
Jeff Fan 2016-07-22 10:28:14 +08:00
parent a1a4c7a467
commit 4b0eeef313
13 changed files with 0 additions and 2669 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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
;-------------------------------------------------------------------------------

View File

@ -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

View File

@ -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