/** Callback function executed when the EndOfDxe event group is signaled. We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe. @param[in] Event Event whose notification function is being invoked. @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in. **/ VOID EFIAPI CpuS3DataOnEndOfDxe ( IN EFI_EVENT Event, OUT VOID *Context ) { EFI_STATUS Status; ACPI_CPU_DATA_EX *AcpiCpuDataEx; AcpiCpuDataEx = (ACPI_CPU_DATA_EX *) Context; // // Allocate a 4KB reserved page below 1MB // AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, 1, &AcpiCpuDataEx->AcpiCpuData.StartupVector ); ASSERT_EFI_ERROR (Status); DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__)); MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable); // // Close event, so it will not be invoked again. // gBS->CloseEvent (Event); }
/** Triggers CPU-only reset and restores processor environment. This function triggers CPU-only reset and restores processor environment. **/ VOID CpuOnlyResetAndRestore ( VOID ) { MTRR_SETTINGS MtrrSetting; MtrrGetAllMtrrs (&MtrrSetting); InitiateCpuOnlyReset (); DispatchAPAndWait ( TRUE, 0, EarlyMpInit ); EarlyMpInit (mCpuConfigConextBuffer.BspNumber); ProgramVirtualWireMode (); }
/** 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; }
/** Display the memory type registers @param [in] SocketFD The socket's file descriptor to add to the list. @param [in] pPort The WSDT_PORT structure address @param [out] pbDone Address to receive the request completion status @retval EFI_SUCCESS The request was successfully processed **/ EFI_STATUS MemoryTypeRegistersPage ( IN int SocketFD, IN WSDT_PORT * pPort, OUT BOOLEAN * pbDone ) { UINT64 Addr; BOOLEAN bValid; MSR_IA32_MTRRCAP_REGISTER Capabilities; UINTN Count; MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType; UINTN Index; UINT64 Mask; CONST UINT64 mFixedAddresses [( 8 * MTRR_NUMBER_OF_FIXED_MTRR ) + 1 ] = { 0ULL, 0x10000ULL, 0x20000ULL, 0x30000ULL, 0x40000ULL, 0x50000ULL, 0x60000ULL, 0x70000ULL, 0x80000ULL, 0x84000ULL, 0x88000ULL, 0x8c000ULL, 0x90000ULL, 0x94000ULL, 0x98000ULL, 0x9c000ULL, 0xa0000ULL, 0xa4000ULL, 0xa8000ULL, 0xac000ULL, 0xb0000ULL, 0xb4000ULL, 0xb8000ULL, 0xbc000ULL, 0xc0000ULL, 0xc1000ULL, 0xc2000ULL, 0xc3000ULL, 0xc4000ULL, 0xc5000ULL, 0xc6000ULL, 0xc7000ULL, 0xc8000ULL, 0xc9000ULL, 0xca000ULL, 0xcb000ULL, 0xcc000ULL, 0xcd000ULL, 0xce000ULL, 0xcf000ULL, 0xd0000ULL, 0xd1000ULL, 0xd2000ULL, 0xd3000ULL, 0xd4000ULL, 0xd5000ULL, 0xd6000ULL, 0xd7000ULL, 0xd8000ULL, 0xd9000ULL, 0xda000ULL, 0xdb000ULL, 0xdc000ULL, 0xdd000ULL, 0xde000ULL, 0xdf000ULL, 0xe0000ULL, 0xe1000ULL, 0xe2000ULL, 0xe3000ULL, 0xe4000ULL, 0xe5000ULL, 0xe6000ULL, 0xe7000ULL, 0xe8000ULL, 0xe9000ULL, 0xea000ULL, 0xeb000ULL, 0xec000ULL, 0xed000ULL, 0xee000ULL, 0xef000ULL, 0xf0000ULL, 0xf1000ULL, 0xf2000ULL, 0xf3000ULL, 0xf4000ULL, 0xf5000ULL, 0xf6000ULL, 0xf7000ULL, 0xf8000ULL, 0xf9000ULL, 0xfa000ULL, 0xfb000ULL, 0xfc000ULL, 0xfd000ULL, 0xfe000ULL, 0xff000ULL, 0x100000ULL }; MTRR_SETTINGS Mtrr; CONST UINT64 * pMemEnd; CONST UINT64 * pMemStart; UINT64 PreviousType; UINT64 ShiftCount; EFI_STATUS Status; UINT64 Type; INT64 Value; DBG_ENTER ( ); // // Send the Memory Type Registers page // for ( ; ; ) { // // Send the page header // Status = HttpPageHeader ( SocketFD, pPort, L"Memory Type Range Registers" ); if ( EFI_ERROR ( Status )) { break; } // // Send the header // Status = HttpSendAnsiString ( SocketFD, pPort, "<h1>Memory Type Range Registers</h1>\r\n" ); if ( EFI_ERROR ( Status )) { break; } // // Determine if MTRRs are supported // if ( !IsMtrrSupported ( )) { Status = HttpSendAnsiString ( SocketFD, pPort, "<p>Memory Type Range Registers are not supported!\r\n" ); if ( EFI_ERROR ( Status )) { break; } } else { // // Get the capabilities // Capabilities.Uint64 = AsmReadMsr64 ( MSR_IA32_MTRRCAP ); DefType.Uint64 = AsmReadMsr64 ( MSR_IA32_MTRR_DEF_TYPE ); // // Display the capabilities // Status = HttpSendAnsiString ( SocketFD, pPort, "<p>Capabilities: " ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, Capabilities.Uint64 ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendAnsiString ( SocketFD, pPort, "<br>\r\n" ); if ( EFI_ERROR ( Status )) { break; } // // Display the default type // Status = HttpSendAnsiString ( SocketFD, pPort, "Def Type: " ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, DefType.Uint64); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendAnsiString ( SocketFD, pPort, ", MTRRs " ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendAnsiString ( SocketFD, pPort, ( 0 != DefType.Bits.E ) ? "Enabled" : "Disabled" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendAnsiString ( SocketFD, pPort, ", Fixed MTRRs " ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendAnsiString ( SocketFD, pPort, ( 0 != DefType.Bits.FE ) ? "Enabled" : "Disabled" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendAnsiString ( SocketFD, pPort, ", " ); if ( EFI_ERROR ( Status )) { break; } Type = DefType.Uint64 & 0xff; Status = HttpSendAnsiString ( SocketFD, pPort, ( DIM ( mMemoryType ) > Type ) ? mMemoryType [ Type ] : "Reserved" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendAnsiString ( SocketFD, pPort, "</p>\r\n" ); if ( EFI_ERROR ( Status )) { break; } // // Determine if MTRRs are enabled // if ( 0 == DefType.Bits.E ) { Status = HttpSendAnsiString ( SocketFD, pPort, "<p>All memory is uncached!</p>\r\n" ); if ( EFI_ERROR ( Status )) { break; } } else { // // Get the MTRRs // MtrrGetAllMtrrs ( &Mtrr ); // // Determine if the fixed MTRRs are supported // if (( 0 != Capabilities.Bits.FIX ) && ( 0 != DefType.Bits.FE)) { // // Beginning of table // Status = HttpSendAnsiString ( SocketFD, pPort, "<h2>Fixed MTRRs</h2>\r\n" "<table>\r\n" " <tr><th>Index</th><th align=\"right\">Value</th><th align=\"right\">Start</th><th align=\"right\">End</th></tr>\r\n" ); if ( EFI_ERROR ( Status )) { break; } // // Display the fixed MTRRs // pMemStart = &mFixedAddresses[ 0 ]; for ( Count = 0; DIM ( Mtrr.Fixed.Mtrr ) > Count; Count++ ) { // // Start the row // Status = HttpSendAnsiString ( SocketFD, pPort, " <tr><td>" ); if ( EFI_ERROR ( Status )) { break; } // // Index // Status = HttpSendValue ( SocketFD, pPort, Count ); if ( EFI_ERROR ( Status )) { break; } // // Value // Status = HttpSendAnsiString ( SocketFD, pPort, "</td><td align=\"right\"><code>0x" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, Mtrr.Fixed.Mtrr[ Count ]); if ( EFI_ERROR ( Status )) { break; } // // Start // Status = HttpSendAnsiString ( SocketFD, pPort, "</code></td><td align=\"right\"><code>0x" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, *pMemStart ); if ( EFI_ERROR ( Status )) { break; } pMemStart += 8; // // Value // Status = HttpSendAnsiString ( SocketFD, pPort, "</code></td><td align=\"right\"><code>0x" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, *pMemStart - 1 ); if ( EFI_ERROR ( Status )) { break; } // // End of row // Status = HttpSendAnsiString ( SocketFD, pPort, "</code></td></tr>\r\n" ); if ( EFI_ERROR ( Status )) { break; } } if ( EFI_ERROR ( Status )) { break; } // // End of table // Status = HttpSendAnsiString ( SocketFD, pPort, "</table>\r\n" ); if ( EFI_ERROR ( Status )) { break; } // // Beginning of table // Status = HttpSendAnsiString ( SocketFD, pPort, "<table>\r\n" " <tr><th align=\"right\">Start</th><th align=\"right\">End</th><th align=\"left\">Type</th></tr>\r\n" ); if ( EFI_ERROR ( Status )) { break; } // // Decode the fixed MTRRs // PreviousType = Mtrr.Fixed.Mtrr[ 0 ] & 0xff; pMemStart = &mFixedAddresses[ 0 ]; pMemEnd = pMemStart; for ( Count = 0; DIM ( Mtrr.Fixed.Mtrr ) > Count; Count++ ) { // // Get the memory types // Type = Mtrr.Fixed.Mtrr[ Count ]; // // Walk the memory range // for ( Index = 0; 8 > Index; Index++ ) { // // Determine if this is the same memory type // if ( PreviousType != ( Type & 0xff )) { // // Display the row // Status = MtrrDisplayFixedRow ( SocketFD, pPort, *pMemStart, *pMemEnd, PreviousType ); if ( EFI_ERROR ( Status )) { break; } // // Start the next range of addresses // pMemStart = pMemEnd; PreviousType = Type & 0xff; } // // Set the next memory range and type // Type >>= 8; pMemEnd += 1; } if ( EFI_ERROR ( Status )) { break; } } if ( EFI_ERROR ( Status )) { break; } // // Display the final row // Status = MtrrDisplayFixedRow ( SocketFD, pPort, *pMemStart, *pMemEnd, PreviousType ); if ( EFI_ERROR ( Status )) { break; } // // End of table // Status = HttpSendAnsiString ( SocketFD, pPort, "</table>\r\n" ); if ( EFI_ERROR ( Status )) { break; } } // // Determine if the variable MTRRs are supported // if ( 0 < Capabilities.Bits.VCNT ) { // // Beginning of table // Status = HttpSendAnsiString ( SocketFD, pPort, "<h2>Variable MTRRs</h2>\r\n" "<table>\r\n" " <tr><th>Index</th><th align=\"right\">Base</th><th align=\"right\">Mask</th><th align=\"right\">Start</th><th align=\"right\">End</th></tr>\r\n" ); if ( EFI_ERROR ( Status )) { break; } // // Display the variable MTRRs // for ( Count = 0; Capabilities.Bits.VCNT > Count; Count++ ) { // // Start the row // Status = HttpSendAnsiString ( SocketFD, pPort, " <tr><td>" ); if ( EFI_ERROR ( Status )) { break; } // // Index // Status = HttpSendValue ( SocketFD, pPort, Count ); if ( EFI_ERROR ( Status )) { break; } // // Base // Status = HttpSendAnsiString ( SocketFD, pPort, "</td><td align=\"right\"><code>0x" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, Mtrr.Variables.Mtrr[ Count ].Base ); if ( EFI_ERROR ( Status )) { break; } // // Mask // Status = HttpSendAnsiString ( SocketFD, pPort, "</td><td align=\"right\"><code>0x" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, Mtrr.Variables.Mtrr[ Count ].Mask ); if ( EFI_ERROR ( Status )) { break; } // // Determine if the entry is valid // bValid = ( Mtrr.Variables.Mtrr[ Count ].Mask & VARIABLE_MTRR_VALID ) ? TRUE : FALSE; // // Start // Status = HttpSendAnsiString ( SocketFD, pPort, "</code></td><td align=\"right\"><code>" ); if ( EFI_ERROR ( Status )) { break; } Addr = Mtrr.Variables.Mtrr[ Count ].Base & 0xfffffffffffff000ULL; if ( bValid ) { Status = HttpSendAnsiString ( SocketFD, pPort, "0x" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, Addr ); } else { Status = HttpSendAnsiString ( SocketFD, pPort, "Invalid" ); } if ( EFI_ERROR ( Status )) { break; } // // End // Status = HttpSendAnsiString ( SocketFD, pPort, "</code></td><td align=\"right\"><code>" ); if ( EFI_ERROR ( Status )) { break; } if ( bValid ) { // // Determine the end address // Mask = Mtrr.Variables.Mtrr[ Count ].Mask; Value = Mask; ShiftCount = 0; while ( 0 < Value ) { Value <<= 1; ShiftCount += 1; } Value = 1; Value <<= 64 - ShiftCount; Value -= 1; Value = ~Value; Value |= Mask; Value &= ~VARIABLE_MTRR_VALID; Value = ~Value; Status = HttpSendAnsiString ( SocketFD, pPort, "0x" ); if ( EFI_ERROR ( Status )) { break; } Status = HttpSendHexValue ( SocketFD, pPort, Addr + Value ); } if ( EFI_ERROR ( Status )) { break; } // // Type // Status = HttpSendAnsiString ( SocketFD, pPort, "</code></td><td>" ); if ( EFI_ERROR ( Status )) { break; } if ( bValid ) { Type = Mtrr.Variables.Mtrr[ Count ].Base & 0xFF; Status = HttpSendAnsiString ( SocketFD, pPort, ( DIM ( mMemoryType ) > Type ) ? mMemoryType [ Type ] : "Reserved" ); } if ( EFI_ERROR ( Status )) { break; } // // End of row // Status = HttpSendAnsiString ( SocketFD, pPort, "</td></tr>\r\n" ); if ( EFI_ERROR ( Status )) { break; } } if ( EFI_ERROR ( Status )) { break; } // // End of table // Status = HttpSendAnsiString ( SocketFD, pPort, "</table>\r\n" ); if ( EFI_ERROR ( Status )) { break; } } } } // // Send the page trailer // Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); break; }
/** 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; }