/** 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 curret executing AP **/ VOID EFIAPI ApCFunction ( IN MP_CPU_EXCHANGE_INFO *ExchangeInfo, IN UINTN NumApsExecuting ) { PEI_CPU_MP_DATA *PeiCpuMpData; UINTN ProcessorNumber; EFI_AP_PROCEDURE Procedure; UINTN BistData; PeiCpuMpData = ExchangeInfo->PeiCpuMpData; if (PeiCpuMpData->InitFlag) { // // This is first time AP wakeup, get BIST information from AP stack // BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData; PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId (); if (PeiCpuMpData->CpuData[NumApsExecuting].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 (); } else { // // Execute AP function if AP is not disabled // GetProcessorNumber (PeiCpuMpData, &ProcessorNumber); if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) && (PeiCpuMpData->ApFunction != 0)) { PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy; Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction; Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument); PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; } } // // AP finished executing C code // InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount); AsmCliHltLoop (); }
/** Replace OS MTRR's with SMI MTRR's. @param CpuIndex Processor Index **/ VOID ReplaceOSMtrrs ( IN UINTN CpuIndex ) { SmmCpuFeaturesDisableSmrr (); // // Replace all MTRRs registers // MtrrSetAllMtrrs (&gSmiMtrrs); }
/** Replace OS MTRR's with SMI MTRR's. @param CpuIndex Processor Index **/ VOID ReplaceOSMtrrs ( IN UINTN CpuIndex ) { PROCESSOR_SMM_DESCRIPTOR *Psd; UINT64 *SmiMtrrs; MTRR_SETTINGS *BiosMtrr; Psd = (PROCESSOR_SMM_DESCRIPTOR*)(mCpuHotPlugData.SmBase[CpuIndex] + SMM_PSD_OFFSET); SmiMtrrs = (UINT64*)(UINTN)Psd->MtrrBaseMaskPtr; SmmCpuFeaturesDisableSmrr (); // // Replace all MTRRs registers // BiosMtrr = (MTRR_SETTINGS*)SmiMtrrs; MtrrSetAllMtrrs(BiosMtrr); }
/** Synch up the MTRR values for all processors. @param MtrrTable Table holding fixed/variable MTRR values to be loaded. **/ VOID EFIAPI LoadMtrrData ( EFI_PHYSICAL_ADDRESS MtrrTable ) /*++ Routine Description: Synch up the MTRR values for all processors. Arguments: Returns: None --*/ { MTRR_SETTINGS *MtrrSettings; MtrrSettings = (MTRR_SETTINGS *) (UINTN) MtrrTable; MtrrSetAllMtrrs (MtrrSettings); }
/** This function will be called from AP reset code if BSP uses WakeUpAP. @param ExchangeInfo Pointer to the MP exchange info buffer @param NumApsExecuting Number of current executing AP **/ VOID EFIAPI ApCFunction ( IN MP_CPU_EXCHANGE_INFO *ExchangeInfo, IN UINTN NumApsExecuting ) { PEI_CPU_MP_DATA *PeiCpuMpData; UINTN ProcessorNumber; EFI_AP_PROCEDURE Procedure; UINTN BistData; volatile UINT32 *ApStartupSignalBuffer; PeiCpuMpData = ExchangeInfo->PeiCpuMpData; while (TRUE) { if (PeiCpuMpData->InitFlag) { ProcessorNumber = NumApsExecuting; // // Sync BSP's Control registers to APs // RestoreVolatileRegisters (&PeiCpuMpData->CpuData[0].VolatileRegisters, FALSE); // // This is first time AP wakeup, get BIST information from AP stack // BistData = *(UINTN *) (PeiCpuMpData->Buffer + ProcessorNumber * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 = (UINT32) BistData; PeiCpuMpData->CpuData[ProcessorNumber].ApicId = GetInitialApicId (); if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId >= 0xFF) { // // Set x2APIC mode if there are any logical processor reporting // an APIC ID of 255 or greater. // AcquireSpinLock(&PeiCpuMpData->MpLock); PeiCpuMpData->X2ApicEnable = TRUE; ReleaseSpinLock(&PeiCpuMpData->MpLock); } // // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs. // MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable); MicrocodeDetect (); PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; } else { // // Execute AP function if AP is not disabled // GetProcessorNumber (PeiCpuMpData, &ProcessorNumber); if (PeiCpuMpData->ApLoopMode == ApInHltLoop) { // // Restore AP's volatile registers saved // RestoreVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE); } if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) && (PeiCpuMpData->ApFunction != 0)) { PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy; Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction; // // Invoke AP function here // Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument); // // Re-get the processor number due to BSP/AP maybe exchange in AP function // GetProcessorNumber (PeiCpuMpData, &ProcessorNumber); PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; } } // // AP finished executing C code // InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount); // // Place AP is specified loop mode // if (PeiCpuMpData->ApLoopMode == ApInHltLoop) { // // Save AP volatile registers // SaveVolatileRegisters (&PeiCpuMpData->CpuData[ProcessorNumber].VolatileRegisters); // // Place AP in Hlt-loop // while (TRUE) { DisableInterrupts (); CpuSleep (); CpuPause (); } } ApStartupSignalBuffer = PeiCpuMpData->CpuData[ProcessorNumber].StartupApSignal; // // Clear AP start-up signal // *ApStartupSignalBuffer = 0; while (TRUE) { DisableInterrupts (); if (PeiCpuMpData->ApLoopMode == ApInMwaitLoop) { // // Place AP in Mwait-loop // AsmMonitor ((UINTN)ApStartupSignalBuffer, 0, 0); if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) { // // If AP start-up signal is not set, place AP into // the maximum C-state // AsmMwait (PeiCpuMpData->ApTargetCState << 4, 0); } } else if (PeiCpuMpData->ApLoopMode == ApInRunLoop) { // // Place AP in Run-loop // CpuPause (); } else { ASSERT (FALSE); } // // If AP start-up signal is written, AP is waken up // otherwise place AP in loop again // if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) { break; } } } }
/** This function will be called when MRC is done. @param PeiServices General purpose services available to every PEIM. @param NotifyDescriptor Information about the notify event.. @param Ppi The notify context. @retval EFI_SUCCESS If the function completed successfully. **/ EFI_STATUS EFIAPI MemoryDiscoveredPpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; UINT64 MemoryLength; UINT64 MemoryLengthUc; UINT64 MaxMemoryLength; UINT64 MemOverflow; EFI_SMRAM_DESCRIPTOR *SmramDescriptor; UINTN NumSmramRegions; UINT64 EnlargedMemoryLength; UINT32 RmuMainBaseAddress; UINTN Index; MTRR_SETTINGS MtrrSetting; UINT32 RegData32; EFI_PHYSICAL_ADDRESS NewBuffer; UINT8 CpuAddressWidth; EFI_CPUID_REGISTER FeatureInfo; DEBUG ((EFI_D_INFO, "Platform PEIM Memory Callback\n")); NumSmramRegions = 0; SmramDescriptor = NULL; RmuMainBaseAddress = 0; PERF_START (NULL, "SetCache", NULL, 0); InfoPostInstallMemory (&RmuMainBaseAddress, &SmramDescriptor, &NumSmramRegions); ASSERT (SmramDescriptor != NULL); ASSERT (RmuMainBaseAddress != 0); MemoryLength = ((UINT64) RmuMainBaseAddress) + 0x10000; EnlargedMemoryLength = MemoryLength; if (NumSmramRegions > 0) { // // Find the TSEG // for (Index = 0; Index < NumSmramRegions; Index ++) { if ((SmramDescriptor[Index].PhysicalStart) == EnlargedMemoryLength) { if (SmramDescriptor[Index].RegionState & EFI_CACHEABLE) { // // Enlarge memory length to include TSEG size // EnlargedMemoryLength += (SmramDescriptor[Index].PhysicalSize); } } } } // // Check if a UC region is present // MaxMemoryLength = EnlargedMemoryLength; // Round up to nearest 256MB MemOverflow = (MemoryLength & 0x0fffffff); if (MemOverflow != 0) { MaxMemoryLength = MemoryLength + (0x10000000 - MemOverflow); } Status = PeiServicesGetBootMode (&BootMode); ASSERT_EFI_ERROR (Status); ZeroMem (&MtrrSetting, sizeof(MTRR_SETTINGS)); (**PeiServices).CopyMem ((VOID *)&MtrrSetting.Fixed,(VOID *)&mFixedMtrrTable, sizeof(MTRR_FIXED_SETTINGS) ); // // Cache the flash area to improve the boot performance in PEI phase // MtrrSetting.Variables.Mtrr[0].Base = (QUARK_BOOTROM_BASE_ADDRESS | CacheWriteBack); MtrrSetting.Variables.Mtrr[0].Mask = (((~(QUARK_BOOTROM_SIZE_BYTES - 1)) & MTRR_LIB_CACHE_VALID_ADDRESS) | MTRR_LIB_CACHE_MTRR_ENABLED); MtrrSetting.Variables.Mtrr[1].Base = CacheWriteBack; MtrrSetting.Variables.Mtrr[1].Mask = ((~(MaxMemoryLength - 1)) & MTRR_LIB_CACHE_VALID_ADDRESS) | MTRR_LIB_CACHE_MTRR_ENABLED; Index = 2; while (MaxMemoryLength != MemoryLength) { MemoryLengthUc = GetPowerOfTwo64 (MaxMemoryLength - MemoryLength); //Status = MtrrSetMemoryAttribute (MaxMemoryLength - MemoryLengthUc, MemoryLengthUc, CacheUncacheable); //ASSERT_EFI_ERROR (Status); MtrrSetting.Variables.Mtrr[Index].Base = ((MaxMemoryLength - MemoryLengthUc) & MTRR_LIB_CACHE_VALID_ADDRESS) | CacheUncacheable; MtrrSetting.Variables.Mtrr[Index].Mask= ((~(MemoryLengthUc - 1)) & MTRR_LIB_CACHE_VALID_ADDRESS) | MTRR_LIB_CACHE_MTRR_ENABLED; MaxMemoryLength -= MemoryLengthUc; Index++; } AsmInvd (); MtrrSetting.MtrrDefType = MTRR_LIB_CACHE_MTRR_ENABLED | MTRR_LIB_CACHE_FIXED_MTRR_ENABLED; MtrrSetAllMtrrs(&MtrrSetting); PERF_END (NULL, "SetCache", NULL, 0); // // Install PeiReset for PeiResetSystem service // Status = PeiServicesInstallPpi (&mPpiList[0]); ASSERT_EFI_ERROR (Status); // // Do QNC initialization after MRC // PeiQNCPostMemInit (); Status = PeiServicesInstallPpi (&mPpiStall[0]); ASSERT_EFI_ERROR (Status); // // Set E000/F000 Routing // RegData32 = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); RegData32 |= (BIT2|BIT1); QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, RegData32); if (BootMode == BOOT_IN_RECOVERY_MODE) { PeiServicesInstallFvInfoPpi ( NULL, (VOID *) (UINTN) PcdGet32 (PcdFlashFvRecovery2Base), PcdGet32 (PcdFlashFvRecovery2Size), NULL, NULL ); Status = PeimInitializeRecovery (PeiServices); ASSERT_EFI_ERROR (Status); } else if (BootMode == BOOT_ON_S3_RESUME) { return EFI_SUCCESS; } else { // // Allocate the memory so that it gets preserved into DXE // Status = PeiServicesAllocatePages ( EfiBootServicesData, EFI_SIZE_TO_PAGES (PcdGet32 (PcdFvSecurityHeaderSize) + PcdGet32 (PcdFlashFvMainSize)), &NewBuffer ); // // Copy the compressed main Firmware Volume to memory for faster processing later // CopyMem ((VOID *) (UINTN) NewBuffer, (VOID *) (UINTN) (PcdGet32 (PcdFlashFvMainBase) - PcdGet32 (PcdFvSecurityHeaderSize)), (PcdGet32 (PcdFvSecurityHeaderSize) +PcdGet32 (PcdFlashFvMainSize))); PeiServicesInstallFvInfoPpi ( NULL, (VOID *) (UINTN) (NewBuffer + PcdGet32 (PcdFvSecurityHeaderSize)), PcdGet32 (PcdFlashFvMainSize), NULL, NULL ); } // // Build flash HOB, it's going to be used by GCD and E820 building // Map full SPI flash decode range (regardless of smaller SPI flash parts installed) // BuildResourceDescriptorHob ( EFI_RESOURCE_FIRMWARE_DEVICE, (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), (SIZE_4GB - SIZE_8MB), SIZE_8MB ); // // Create a CPU hand-off information // CpuAddressWidth = 32; AsmCpuid (EFI_CPUID_EXTENDED_FUNCTION, &FeatureInfo.RegEax, NULL, NULL, NULL); if (FeatureInfo.RegEax >= EFI_CPUID_VIR_PHY_ADDRESS_SIZE) { AsmCpuid (EFI_CPUID_VIR_PHY_ADDRESS_SIZE, &FeatureInfo.RegEax, NULL, NULL, NULL); CpuAddressWidth = (UINT8) (FeatureInfo.RegEax & 0xFF); } DEBUG ((EFI_D_INFO, "CpuAddressWidth: %d\n", CpuAddressWidth)); BuildCpuHob (CpuAddressWidth, 16); ASSERT_EFI_ERROR (Status); return Status; }
/** This function will be called when MRC is done. @param PeiServices General purpose services available to every PEIM. @param NotifyDescriptor Information about the notify event.. @param Ppi The notify context. @retval EFI_SUCCESS If the function completed successfully. **/ EFI_STATUS EFIAPI MemoryDiscoveredPpiNotifyCallback ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { EFI_STATUS Status; EFI_BOOT_MODE BootMode; UINT64 MemoryLength; EFI_SMRAM_DESCRIPTOR *SmramDescriptor; UINTN NumSmramRegions; UINT32 RmuMainBaseAddress; UINT32 RegData32; UINT8 CpuAddressWidth; UINT32 RegEax; MTRR_SETTINGS MtrrSettings; EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices; UINT8 MorControl; UINTN DataSize; DEBUG ((EFI_D_INFO, "Platform PEIM Memory Callback\n")); NumSmramRegions = 0; SmramDescriptor = NULL; RmuMainBaseAddress = 0; PERF_START (NULL, "SetCache", NULL, 0); InfoPostInstallMemory (&RmuMainBaseAddress, &SmramDescriptor, &NumSmramRegions); ASSERT (SmramDescriptor != NULL); ASSERT (RmuMainBaseAddress != 0); MemoryLength = ((UINT64) RmuMainBaseAddress) + 0x10000; Status = PeiServicesGetBootMode (&BootMode); ASSERT_EFI_ERROR (Status); // // Get current MTRR settings // MtrrGetAllMtrrs (&MtrrSettings); // // Set all DRAM cachability to CacheWriteBack // Status = MtrrSetMemoryAttributeInMtrrSettings (&MtrrSettings, 0, MemoryLength, CacheWriteBack); ASSERT_EFI_ERROR (Status); // // RTC:28208 - System hang/crash when entering probe mode(ITP) when relocating SMBASE // Workaround to make default SMRAM UnCachable // Status = MtrrSetMemoryAttributeInMtrrSettings (&MtrrSettings, 0x30000, SIZE_64KB, CacheUncacheable); ASSERT_EFI_ERROR (Status); // // Set new MTRR settings // MtrrSetAllMtrrs (&MtrrSettings); PERF_END (NULL, "SetCache", NULL, 0); // // Get necessary PPI // Status = PeiServicesLocatePpi ( &gEfiPeiReadOnlyVariable2PpiGuid, // GUID 0, // INSTANCE NULL, // EFI_PEI_PPI_DESCRIPTOR (VOID **)&VariableServices // PPI ); ASSERT_EFI_ERROR (Status); // // Detect MOR request by the OS. // MorControl = 0; DataSize = sizeof (MorControl); Status = VariableServices->GetVariable ( VariableServices, MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid, NULL, &DataSize, &MorControl ); // // If OS requested a memory overwrite perform it now for Embedded SRAM // if (MOR_CLEAR_MEMORY_VALUE (MorControl)) { DEBUG ((EFI_D_INFO, "Clear Embedded SRAM per MOR request.\n")); if (PcdGet32 (PcdESramMemorySize) > 0) { if (PcdGet32 (PcdEsramStage1Base) == 0) { // // ZeroMem() generates an ASSERT() if Buffer parameter is NULL. // Clear byte at 0 and start clear operation at address 1. // *(UINT8 *)(0) = 0; ZeroMem ((VOID *)1, (UINTN)PcdGet32 (PcdESramMemorySize) - 1); } else { ZeroMem ( (VOID *)(UINTN)PcdGet32 (PcdEsramStage1Base), (UINTN)PcdGet32 (PcdESramMemorySize) ); } } } // // Install PeiReset for PeiResetSystem service // Status = PeiServicesInstallPpi (&mPpiList[0]); ASSERT_EFI_ERROR (Status); // // Do QNC initialization after MRC // PeiQNCPostMemInit (); Status = PeiServicesInstallPpi (&mPpiStall[0]); ASSERT_EFI_ERROR (Status); // // Set E000/F000 Routing // RegData32 = QNCPortRead (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC); RegData32 |= (BIT2|BIT1); QNCPortWrite (QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HMISC, RegData32); if (BootMode == BOOT_IN_RECOVERY_MODE) { // Do nothing here. A generic RecoveryModule will handle it. } else if (BootMode == BOOT_ON_S3_RESUME) { return EFI_SUCCESS; } else { PeiServicesInstallFvInfoPpi ( NULL, (VOID *) (UINTN) PcdGet32 (PcdFlashFvMainBase), PcdGet32 (PcdFlashFvMainSize), NULL, NULL ); // // Publish the FVMAIN FV so the DXE Phase can dispatch drivers from this FV // and produce Load File Protocols for UEFI Applications in this FV. // BuildFvHob ( PcdGet32 (PcdFlashFvMainBase), PcdGet32 (PcdFlashFvMainSize) ); // // Publish the Payload FV so the DXE Phase can dispatch drivers from this FV // and produce Load File Protocols for UEFI Applications in this FV. // BuildFvHob ( PcdGet32 (PcdFlashFvPayloadBase), PcdGet32 (PcdFlashFvPayloadSize) ); } // // Build flash HOB, it's going to be used by GCD and E820 building // Map full SPI flash decode range (regardless of smaller SPI flash parts installed) // BuildResourceDescriptorHob ( EFI_RESOURCE_FIRMWARE_DEVICE, (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE), (SIZE_4GB - SIZE_8MB), SIZE_8MB ); // // Create a CPU hand-off information // CpuAddressWidth = 32; AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL); if (RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) { AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL); CpuAddressWidth = (UINT8) (RegEax & 0xFF); } DEBUG ((EFI_D_INFO, "CpuAddressWidth: %d\n", CpuAddressWidth)); BuildCpuHob (CpuAddressWidth, 16); ASSERT_EFI_ERROR (Status); return Status; }
/** SMI handler for AP. @param CpuIndex AP processor Index. @param ValidSmi Indicates that current SMI is a valid SMI or not. @param SyncMode SMM MP sync mode. **/ VOID APHandler ( IN UINTN CpuIndex, IN BOOLEAN ValidSmi, IN SMM_CPU_SYNC_MODE SyncMode ) { UINT64 Timer; UINTN BspIndex; MTRR_SETTINGS Mtrrs; // // Timeout BSP // for (Timer = StartSyncTimer (); !IsSyncTimerTimeout (Timer) && !mSmmMpSyncData->InsideSmm; ) { CpuPause (); } if (!mSmmMpSyncData->InsideSmm) { // // BSP timeout in the first round // if (mSmmMpSyncData->BspIndex != -1) { // // BSP Index is known // BspIndex = mSmmMpSyncData->BspIndex; ASSERT (CpuIndex != BspIndex); // // Send SMI IPI to bring BSP in // SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[BspIndex].ProcessorId); // // Now clock BSP for the 2nd time // for (Timer = StartSyncTimer (); !IsSyncTimerTimeout (Timer) && !mSmmMpSyncData->InsideSmm; ) { CpuPause (); } if (!mSmmMpSyncData->InsideSmm) { // // Give up since BSP is unable to enter SMM // and signal the completion of this AP WaitForSemaphore (&mSmmMpSyncData->Counter); return; } } else { // // Don't know BSP index. Give up without sending IPI to BSP. // WaitForSemaphore (&mSmmMpSyncData->Counter); return; } } // // BSP is available // BspIndex = mSmmMpSyncData->BspIndex; ASSERT (CpuIndex != BspIndex); // // Mark this processor's presence // mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE; if (SyncMode == SmmCpuSyncModeTradition || SmmCpuFeaturesNeedConfigureMtrrs()) { // // Notify BSP of arrival at this point // ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); } if (SmmCpuFeaturesNeedConfigureMtrrs()) { // // Wait for the signal from BSP to backup MTRRs // WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); // // Backup OS MTRRs // MtrrGetAllMtrrs(&Mtrrs); // // Signal BSP the completion of this AP // ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); // // Wait for BSP's signal to program MTRRs // WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); // // Replace OS MTRRs with SMI MTRRs // ReplaceOSMtrrs (CpuIndex); // // Signal BSP the completion of this AP // ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); } while (TRUE) { // // Wait for something to happen // WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); // // Check if BSP wants to exit SMM // if (!mSmmMpSyncData->InsideSmm) { break; } // // BUSY should be acquired by SmmStartupThisAp() // ASSERT ( !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy) ); // // Invoke the scheduled procedure // (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) ( (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter ); // // Release BUSY // ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy); } if (SmmCpuFeaturesNeedConfigureMtrrs()) { // // Notify BSP the readiness of this AP to program MTRRs // ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); // // Wait for the signal from BSP to program MTRRs // WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); // // Restore OS MTRRs // SmmCpuFeaturesReenableSmrr (); MtrrSetAllMtrrs(&Mtrrs); } // // Notify BSP the readiness of this AP to Reset states/semaphore for this processor // ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); // // Wait for the signal from BSP to Reset states/semaphore for this processor // WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run); // // Reset states/semaphore for this processor // mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE; // // Notify BSP the readiness of this AP to exit SMM // ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run); }
/** SMI handler for BSP. @param CpuIndex BSP processor Index @param SyncMode SMM MP sync mode **/ VOID BSPHandler ( IN UINTN CpuIndex, IN SMM_CPU_SYNC_MODE SyncMode ) { UINTN Index; MTRR_SETTINGS Mtrrs; UINTN ApCount; BOOLEAN ClearTopLevelSmiResult; UINTN PresentCount; ASSERT (CpuIndex == mSmmMpSyncData->BspIndex); ApCount = 0; // // Flag BSP's presence // mSmmMpSyncData->InsideSmm = TRUE; // // Initialize Debug Agent to start source level debug in BSP handler // InitializeDebugAgent (DEBUG_AGENT_INIT_ENTER_SMI, NULL, NULL); // // Mark this processor's presence // mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE; // // Clear platform top level SMI status bit before calling SMI handlers. If // we cleared it after SMI handlers are run, we would miss the SMI that // occurs after SMI handlers are done and before SMI status bit is cleared. // ClearTopLevelSmiResult = ClearTopLevelSmiStatus(); ASSERT (ClearTopLevelSmiResult == TRUE); // // Set running processor index // gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu = CpuIndex; // // If Traditional Sync Mode or need to configure MTRRs: gather all available APs. // if (SyncMode == SmmCpuSyncModeTradition || SmmCpuFeaturesNeedConfigureMtrrs()) { // // Wait for APs to arrive // SmmWaitForApArrival(); // // Lock the counter down and retrieve the number of APs // mSmmMpSyncData->AllCpusInSync = TRUE; ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1; // // Wait for all APs to get ready for programming MTRRs // WaitForAllAPs (ApCount); if (SmmCpuFeaturesNeedConfigureMtrrs()) { // // Signal all APs it's time for backup MTRRs // ReleaseAllAPs (); // // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set // to a large enough value to avoid this situation. // Note: For HT capable CPUs, threads within a core share the same set of MTRRs. // We do the backup first and then set MTRR to avoid race condition for threads // in the same core. // MtrrGetAllMtrrs(&Mtrrs); // // Wait for all APs to complete their MTRR saving // WaitForAllAPs (ApCount); // // Let all processors program SMM MTRRs together // ReleaseAllAPs (); // // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set // to a large enough value to avoid this situation. // ReplaceOSMtrrs (CpuIndex); // // Wait for all APs to complete their MTRR programming // WaitForAllAPs (ApCount); } } // // The BUSY lock is initialized to Acquired state // AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy); // // Restore SMM Configuration in S3 boot path. // if (mRestoreSmmConfigurationInS3) { // // Configure SMM Code Access Check feature if available. // ConfigSmmCodeAccessCheck (); mRestoreSmmConfigurationInS3 = FALSE; } // // Invoke SMM Foundation EntryPoint with the processor information context. // gSmmCpuPrivate->SmmCoreEntry (&gSmmCpuPrivate->SmmCoreEntryContext); // // Make sure all APs have completed their pending none-block tasks // for (Index = mMaxNumberOfCpus; Index-- > 0;) { if (Index != CpuIndex && mSmmMpSyncData->CpuData[Index].Present) { AcquireSpinLock (&mSmmMpSyncData->CpuData[Index].Busy); ReleaseSpinLock (&mSmmMpSyncData->CpuData[Index].Busy);; } } // // Perform the remaining tasks // PerformRemainingTasks (); // // If Relaxed-AP Sync Mode: gather all available APs after BSP SMM handlers are done, and // make those APs to exit SMI synchronously. APs which arrive later will be excluded and // will run through freely. // if (SyncMode != SmmCpuSyncModeTradition && !SmmCpuFeaturesNeedConfigureMtrrs()) { // // Lock the counter down and retrieve the number of APs // mSmmMpSyncData->AllCpusInSync = TRUE; ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1; // // Make sure all APs have their Present flag set // while (TRUE) { PresentCount = 0; for (Index = mMaxNumberOfCpus; Index-- > 0;) { if (mSmmMpSyncData->CpuData[Index].Present) { PresentCount ++; } } if (PresentCount > ApCount) { break; } } } // // Notify all APs to exit // mSmmMpSyncData->InsideSmm = FALSE; ReleaseAllAPs (); // // Wait for all APs to complete their pending tasks // WaitForAllAPs (ApCount); if (SmmCpuFeaturesNeedConfigureMtrrs()) { // // Signal APs to restore MTRRs // ReleaseAllAPs (); // // Restore OS MTRRs // SmmCpuFeaturesReenableSmrr (); MtrrSetAllMtrrs(&Mtrrs); // // Wait for all APs to complete MTRR programming // WaitForAllAPs (ApCount); } // // Stop source level debug in BSP handler, the code below will not be // debugged. // InitializeDebugAgent (DEBUG_AGENT_INIT_EXIT_SMI, NULL, NULL); // // Signal APs to Reset states/semaphore for this processor // ReleaseAllAPs (); // // Perform pending operations for hot-plug // SmmCpuUpdate (); // // Clear the Present flag of BSP // mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE; // // Gather APs to exit SMM synchronously. Note the Present flag is cleared by now but // WaitForAllAps does not depend on the Present flag. // WaitForAllAPs (ApCount); // // Reset BspIndex to -1, meaning BSP has not been elected. // if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) { mSmmMpSyncData->BspIndex = (UINT32)-1; } // // Allow APs to check in from this point on // mSmmMpSyncData->Counter = 0; mSmmMpSyncData->AllCpusInSync = FALSE; }
EFI_STATUS EFIAPI SetPeiCacheMode ( IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; PEI_CACHE_PPI *CachePpi; EFI_BOOT_MODE BootMode; UINT64 MemoryLength; UINT64 MemOverflow; UINT64 MemoryLengthUc; UINT64 MaxMemoryLength; UINT64 LowMemoryLength; UINT64 HighMemoryLength; UINT8 Index; MTRR_SETTINGS MtrrSetting; UINT64 ValidMtrrAddressMask; // // Load Cache PPI // Status = (**PeiServices).LocatePpi ( PeiServices, &gPeiCachePpiGuid, // GUID 0, // Instance NULL, // EFI_PEI_PPI_DESCRIPTOR (void **)&CachePpi // PPI ); if (!EFI_ERROR(Status)) { // // Clear the CAR Settings (Default Cache Type => UC) // DEBUG ((EFI_D_INFO, "Reset cache attribute and disable CAR. \n")); CachePpi->ResetCache( (EFI_PEI_SERVICES**)PeiServices, CachePpi ); } // // Variable initialization // LowMemoryLength = 0; HighMemoryLength = 0; MemoryLengthUc = 0; Status = (*PeiServices)->GetBootMode ( PeiServices, &BootMode ); ValidMtrrAddressMask = InitializeAddressMtrrMask (); // // Determine memory usage // GetMemorySize ( PeiServices, &LowMemoryLength, &HighMemoryLength ); LowMemoryLength = (EFI_PHYSICAL_ADDRESS)MmPci32( 0, 0, 2, 0, 0x70); LowMemoryLength &= 0xFFF00000ULL; MaxMemoryLength = LowMemoryLength; // // Round up to nearest 256MB with high memory and 64MB w/o high memory // if (HighMemoryLength != 0 ) { MemOverflow = (LowMemoryLength & 0x0fffffff); if (MemOverflow != 0) { MaxMemoryLength = LowMemoryLength + (0x10000000 - MemOverflow); } } else { MemOverflow = (LowMemoryLength & 0x03ffffff); if (MemOverflow != 0) { MaxMemoryLength = LowMemoryLength + (0x4000000 - MemOverflow); } } ZeroMem (&MtrrSetting, sizeof(MTRR_SETTINGS)); for (Index = 0; Index < 2; Index++) { MtrrSetting.Fixed.Mtrr[Index]=0x0606060606060606; } for (Index = 2; Index < 11; Index++) { MtrrSetting.Fixed.Mtrr[Index]=0x0505050505050505; } // // Cache the flash area to improve the boot performance in PEI phase // Index = 0; ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[0].Base)->Uint64 = FixedPcdGet32 (PcdFlashAreaBaseAddress); ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[0].Base)->Bits.Type = CacheWriteProtected; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[0].Mask)->Uint64 = (~((UINT64)(FixedPcdGet32 (PcdFlashAreaSize) - 1))) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[0].Mask)->Bits.V = 1; Index ++; MemOverflow =0; while (MaxMemoryLength > MemOverflow){ MemoryLength = MaxMemoryLength - MemOverflow; MemoryLength = GetPowerOfTwo64 (MemoryLength); ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Uint64 = MemOverflow & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Bits.Type = CacheWriteBack; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Uint64 = (~(MemoryLength - 1)) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Bits.V = 1; MemOverflow += MemoryLength; Index++; } MemoryLength = LowMemoryLength; while (MaxMemoryLength != MemoryLength) { MemoryLengthUc = GetPowerOfTwo64 (MaxMemoryLength - MemoryLength); ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Uint64 = (MaxMemoryLength - MemoryLengthUc) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Bits.Type = CacheUncacheable; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Uint64 = (~(MemoryLengthUc - 1)) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Bits.V = 1; MaxMemoryLength -= MemoryLengthUc; Index++; } MemOverflow =0x100000000; while (HighMemoryLength > 0) { MemoryLength = HighMemoryLength; MemoryLength = GetPowerOfTwo64 (MemoryLength); if (MemoryLength > MemOverflow){ MemoryLength = MemOverflow; } ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Uint64 = MemOverflow & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Base)->Bits.Type = CacheWriteBack; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Uint64 = (~(MemoryLength - 1)) & ValidMtrrAddressMask; ((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &MtrrSetting.Variables.Mtrr[Index].Mask)->Bits.V = 1; MemOverflow += MemoryLength; HighMemoryLength -= MemoryLength; Index++; } for (Index = 0; Index < MTRR_NUMBER_OF_VARIABLE_MTRR; Index++) { if (MtrrSetting.Variables.Mtrr[Index].Base == 0){ break; } DEBUG ((EFI_D_INFO, "Base=%lx, Mask=%lx\n",MtrrSetting.Variables.Mtrr[Index].Base ,MtrrSetting.Variables.Mtrr[Index].Mask)); } // // set FE/E bits for IA32_MTRR_DEF_TYPE // MtrrSetting.MtrrDefType |= 3 <<10; MtrrSetAllMtrrs(&MtrrSetting); // // Dump MTRR Setting // MtrrDebugPrintAllMtrrs (); return EFI_SUCCESS; }