audk/StandaloneMmPkg/Drivers/StandaloneMmIplPei/StandaloneMmIplPei.c

828 lines
26 KiB
C

/** @file
MM IPL that load the MM Core into MMRAM at PEI stage
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "StandaloneMmIplPei.h"
EFI_PEI_MM_COMMUNICATION_PPI mMmCommunicationPpi = { Communicate };
EFI_PEI_PPI_DESCRIPTOR mPpiList = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gEfiPeiMmCommunicationPpiGuid,
&mMmCommunicationPpi
};
EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
&gEfiEndOfPeiSignalPpiGuid,
EndOfPeiCallback
};
/**
Communicates with a registered handler.
This function provides a service to send and receive messages from a registered UEFI service.
@param[in] This The EFI_PEI_MM_COMMUNICATION_PPI instance.
@param[in, out] CommBuffer A pointer to the buffer to convey into MMRAM.
@param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
being returned. Zero if the handler does not wish to reply with any data.
@retval EFI_SUCCESS The message was successfully posted.
@retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
@retval EFI_NOT_STARTED The service is NOT started.
**/
EFI_STATUS
EFIAPI
Communicate (
IN CONST EFI_PEI_MM_COMMUNICATION_PPI *This,
IN OUT VOID *CommBuffer,
IN OUT UINTN *CommSize
)
{
EFI_STATUS Status;
EFI_PEI_MM_CONTROL_PPI *MmControl;
UINT8 SmiCommand;
UINTN Size;
UINTN TempCommSize;
EFI_HOB_GUID_TYPE *GuidHob;
MM_COMM_BUFFER *MmCommBuffer;
MM_COMM_BUFFER_STATUS *MmCommBufferStatus;
DEBUG ((DEBUG_INFO, "StandaloneMmIpl Communicate Enter\n"));
GuidHob = GetFirstGuidHob (&gMmCommBufferHobGuid);
if (GuidHob != NULL) {
MmCommBuffer = GET_GUID_HOB_DATA (GuidHob);
MmCommBufferStatus = (MM_COMM_BUFFER_STATUS *)(UINTN)MmCommBuffer->Status;
} else {
DEBUG ((DEBUG_ERROR, "MmCommBuffer is not existed !!!\n"));
ASSERT (GuidHob != NULL);
return EFI_NOT_FOUND;
}
SmiCommand = 0;
Size = sizeof (SmiCommand);
//
// Check parameters
//
if ((CommBuffer == NULL) || (CommSize == NULL)) {
return EFI_INVALID_PARAMETER;
} else {
TempCommSize = *CommSize;
//
// CommSize must hold HeaderGuid and MessageLength
//
if (TempCommSize < OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data)) {
return EFI_INVALID_PARAMETER;
}
}
if (TempCommSize > EFI_PAGES_TO_SIZE (MmCommBuffer->NumberOfPages)) {
DEBUG ((DEBUG_ERROR, "Communicate buffer size (%d) is over MAX (%d) size!", TempCommSize, EFI_PAGES_TO_SIZE (MmCommBuffer->NumberOfPages)));
return EFI_INVALID_PARAMETER;
}
CopyMem ((VOID *)(UINTN)MmCommBuffer->PhysicalStart, CommBuffer, TempCommSize);
MmCommBufferStatus->IsCommBufferValid = TRUE;
//
// Generate Software SMI
//
Status = PeiServicesLocatePpi (&gEfiPeiMmControlPpiGuid, 0, NULL, (VOID **)&MmControl);
ASSERT_EFI_ERROR (Status);
Status = MmControl->Trigger (
(EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
MmControl,
(INT8 *)&SmiCommand,
&Size,
FALSE,
0
);
ASSERT_EFI_ERROR (Status);
//
// Return status from software SMI
//
*CommSize = (UINTN)MmCommBufferStatus->ReturnBufferSize;
//
// Copy the returned data to the non-mmram buffer (CommBuffer)
//
CopyMem (CommBuffer, (VOID *)(MmCommBuffer->PhysicalStart), *CommSize);
Status = (EFI_STATUS)MmCommBufferStatus->ReturnStatus;
if (Status != EFI_SUCCESS) {
DEBUG ((DEBUG_ERROR, "StandaloneMmIpl Communicate failed (%r)\n", Status));
} else {
MmCommBufferStatus->IsCommBufferValid = FALSE;
}
return Status;
}
/**
Search all the available firmware volumes for MM Core driver.
@param MmFvBase Base address of FV which included MM Core driver.
@param MmFvSize Size of FV which included MM Core driver.
@param MmCoreFileName GUID of MM Core.
@param MmCoreImageAddress MM Core image address.
@retval EFI_SUCCESS The specified FFS section was returned.
@retval EFI_NOT_FOUND The specified FFS section could not be found.
**/
EFI_STATUS
LocateMmCoreFv (
OUT EFI_PHYSICAL_ADDRESS *MmFvBase,
OUT UINTN *MmFvSize,
OUT EFI_GUID *MmCoreFileName,
OUT VOID **MmCoreImageAddress
)
{
EFI_STATUS Status;
UINTN FvIndex;
EFI_PEI_FV_HANDLE VolumeHandle;
EFI_PEI_FILE_HANDLE FileHandle;
EFI_PE32_SECTION *SectionData;
EFI_FV_INFO VolumeInfo;
MM_CORE_FV_LOCATION_PPI *MmCoreFvLocation;
//
// The producer of the MmCoreFvLocation PPI is responsible for ensuring
// that it reports the correct Firmware Volume (FV) containing the MmCore.
// If the gMmCoreFvLocationPpiGuid is not found, the system will search
// all Firmware Volumes (FVs) to locate the FV that contains the MM Core.
//
Status = PeiServicesLocatePpi (&gMmCoreFvLocationPpiGuid, 0, NULL, (VOID **)&MmCoreFvLocation);
if (Status == EFI_SUCCESS) {
*MmFvBase = MmCoreFvLocation->Address;
*MmFvSize = MmCoreFvLocation->Size;
FileHandle = NULL;
Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_MM_CORE_STANDALONE, (VOID *)(UINTN)MmCoreFvLocation->Address, &FileHandle);
ASSERT_EFI_ERROR (Status);
if (Status == EFI_SUCCESS) {
ASSERT (FileHandle != NULL);
if (FileHandle != NULL) {
CopyGuid (MmCoreFileName, &((EFI_FFS_FILE_HEADER *)FileHandle)->Name);
//
// Search Section
//
Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, MmCoreImageAddress);
ASSERT_EFI_ERROR (Status);
//
// Get MM Core section data.
//
SectionData = (EFI_PE32_SECTION *)((UINT8 *)*MmCoreImageAddress - sizeof (EFI_PE32_SECTION));
ASSERT (SectionData->Type == EFI_SECTION_PE32);
}
}
return EFI_SUCCESS;
}
//
// Search all FV
//
VolumeHandle = NULL;
for (FvIndex = 0; ; FvIndex++) {
Status = PeiServicesFfsFindNextVolume (FvIndex, &VolumeHandle);
if (EFI_ERROR (Status)) {
break;
}
//
// Search MM Core FFS
//
FileHandle = NULL;
Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_MM_CORE_STANDALONE, VolumeHandle, &FileHandle);
if (EFI_ERROR (Status)) {
continue;
}
ASSERT (FileHandle != NULL);
if (FileHandle != NULL) {
CopyGuid (MmCoreFileName, &((EFI_FFS_FILE_HEADER *)FileHandle)->Name);
}
//
// Search Section
//
Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, MmCoreImageAddress);
if (EFI_ERROR (Status)) {
continue;
}
//
// Get MM Core section data.
//
SectionData = (EFI_PE32_SECTION *)((UINT8 *)*MmCoreImageAddress - sizeof (EFI_PE32_SECTION));
ASSERT (SectionData->Type == EFI_SECTION_PE32);
//
// This is the FV that contains MM Core.
//
Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
if (!EFI_ERROR (Status)) {
*MmFvBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VolumeInfo.FvStart;
*MmFvSize = VolumeInfo.FvSize;
return EFI_SUCCESS;
} else {
return EFI_NOT_FOUND;
}
}
return EFI_NOT_FOUND;
}
/**
Create HOB list for Standalone MM core.
@param[out] HobSize HOB size of fundation and platform HOB list.
@param[in] MmCommBuffer Pointer of MM communication buffer.
@param[in] MmFvBase Base of MM FV which included MM core driver.
@param[in] MmFvSize Size of MM FV which included MM core driver.
@param[in] MmCoreFileName File GUID of MM core driver.
@param[in] MmCoreImageAddress Address of MM core image.
@param[in] MmCoreImageSize Size of MM core image.
@param[in] MmCoreEntryPoint Entry point of MM core driver.
@param[in] Block Pointer of MMRAM descriptor block.
@retval HobList If fundation and platform HOBs not existed,
it is pointed to PEI HOB List. If existed,
it is pointed to fundation and platform HOB list.
**/
VOID *
CreatMmHobList (
OUT UINTN *HobSize,
IN MM_COMM_BUFFER *MmCommBuffer,
IN EFI_PHYSICAL_ADDRESS MmFvBase,
IN UINT64 MmFvSize,
IN EFI_GUID *MmCoreFileName,
IN PHYSICAL_ADDRESS MmCoreImageAddress,
IN UINT64 MmCoreImageSize,
IN PHYSICAL_ADDRESS MmCoreEntryPoint,
IN EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *Block
)
{
EFI_STATUS Status;
VOID *HobList;
VOID *PlatformHobList;
UINTN PlatformHobSize;
UINTN BufferSize;
UINTN FoundationHobSize;
EFI_HOB_MEMORY_ALLOCATION *MmProfileDataHob;
//
// Get platform HOBs
//
PlatformHobSize = 0;
Status = CreateMmPlatformHob (NULL, &PlatformHobSize);
if (Status == RETURN_BUFFER_TOO_SMALL) {
ASSERT (PlatformHobSize != 0);
//
// Create platform HOBs for MM foundation to get MMIO HOB data.
//
PlatformHobList = AllocatePages (EFI_SIZE_TO_PAGES (PlatformHobSize));
ASSERT (PlatformHobList != NULL);
if (PlatformHobList == NULL) {
DEBUG ((DEBUG_ERROR, "%a: Out of resource to create platform MM HOBs\n", __func__));
CpuDeadLoop ();
}
BufferSize = PlatformHobSize;
Status = CreateMmPlatformHob (PlatformHobList, &PlatformHobSize);
ASSERT_EFI_ERROR (Status);
ASSERT (BufferSize == PlatformHobSize);
}
ASSERT_EFI_ERROR (Status);
//
// Build memory allocation HOB in PEI HOB list for MM profile data.
//
MmProfileDataHob = NULL;
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
MmProfileDataHob = BuildMmProfileDataHobInPeiHobList ();
}
//
// Get size of foundation HOBs
//
FoundationHobSize = 0;
Status = CreateMmFoundationHobList (
NULL,
&FoundationHobSize,
PlatformHobList,
PlatformHobSize,
MmFvBase,
MmFvSize,
MmCoreFileName,
MmCoreImageAddress,
MmCoreImageSize,
MmCoreEntryPoint,
MmProfileDataHob,
Block
);
FreePages (PlatformHobList, EFI_SIZE_TO_PAGES (PlatformHobSize));
ASSERT (Status == RETURN_BUFFER_TOO_SMALL);
ASSERT (FoundationHobSize != 0);
//
// Final result includes platform HOBs, foundation HOBs and a END node.
//
*HobSize = PlatformHobSize + FoundationHobSize + sizeof (EFI_HOB_GENERIC_HEADER);
HobList = AllocatePages (EFI_SIZE_TO_PAGES (*HobSize));
ASSERT (HobList != NULL);
if (HobList == NULL) {
DEBUG ((DEBUG_ERROR, "Out of resource to create MM HOBs\n"));
CpuDeadLoop ();
}
//
// Get platform HOBs
//
Status = CreateMmPlatformHob (HobList, &PlatformHobSize);
ASSERT_EFI_ERROR (Status);
//
// Get foundation HOBs
//
Status = CreateMmFoundationHobList (
(UINT8 *)HobList + PlatformHobSize,
&FoundationHobSize,
HobList,
PlatformHobSize,
MmFvBase,
MmFvSize,
MmCoreFileName,
MmCoreImageAddress,
MmCoreImageSize,
MmCoreEntryPoint,
MmProfileDataHob,
Block
);
ASSERT_EFI_ERROR (Status);
//
// Create MM HOB list end.
//
MmIplCreateHob ((UINT8 *)HobList + PlatformHobSize + FoundationHobSize, EFI_HOB_TYPE_END_OF_HOB_LIST, sizeof (EFI_HOB_GENERIC_HEADER));
return HobList;
}
/**
Find largest unallocated MMRAM in current MMRAM descriptor block
@param[in, out] LagestMmramRangeIndex Lagest mmram range index.
@param[in] CurrentBlock Current MMRAM descriptor block.
**/
VOID
FindLargestMmramRange (
IN OUT UINTN *LagestMmramRangeIndex,
IN EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *CurrentBlock
)
{
UINTN Index;
UINT64 MaxSize;
BOOLEAN Found;
EFI_MMRAM_DESCRIPTOR *MmramRanges;
MmramRanges = CurrentBlock->Descriptor;
//
// Find largest Mmram range.
//
Found = FALSE;
for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < CurrentBlock->NumberOfMmReservedRegions; Index++) {
//
// Skip any MMRAM region that is already allocated, needs testing, or needs ECC initialization
//
if ((MmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
continue;
}
if (MmramRanges[Index].CpuStart >= BASE_1MB) {
if ((MmramRanges[Index].CpuStart + MmramRanges[Index].PhysicalSize) <= BASE_4GB) {
if (MmramRanges[Index].PhysicalSize >= MaxSize) {
Found = TRUE;
*LagestMmramRangeIndex = Index;
MaxSize = MmramRanges[Index].PhysicalSize;
}
}
}
}
if (Found == FALSE) {
DEBUG ((DEBUG_ERROR, "Not found largest unlocated MMRAM\n"));
ASSERT (FALSE);
CpuDeadLoop ();
}
return;
}
/**
Allocate available MMRAM for MM core image.
@param[in] Pages Page count of MM core image.
@param[out] NewBlock Pointer of new mmram block HOB.
@return EFI_PHYSICAL_ADDRESS Address for MM core image to be loaded in MMRAM.
**/
EFI_PHYSICAL_ADDRESS
MmIplAllocateMmramPage (
IN UINTN Pages,
OUT EFI_MMRAM_HOB_DESCRIPTOR_BLOCK **NewBlock
)
{
UINTN LagestMmramRangeIndex;
UINT32 FullMmramRangeCount;
EFI_HOB_GUID_TYPE *MmramInfoHob;
EFI_MMRAM_DESCRIPTOR *Largest;
EFI_MMRAM_DESCRIPTOR *Allocated;
EFI_MMRAM_DESCRIPTOR *FullMmramRanges;
EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *CurrentBlock;
EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *NewDescriptorBlock;
MmramInfoHob = GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);
ASSERT (MmramInfoHob != NULL);
if (MmramInfoHob == NULL) {
DEBUG ((DEBUG_WARN, "SmramMemoryReserve HOB not found\n"));
return 0;
}
CurrentBlock = (EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *)(GET_GUID_HOB_DATA (MmramInfoHob));
//
// 1. Find largest unallocated MMRAM region
//
FindLargestMmramRange (&LagestMmramRangeIndex, CurrentBlock);
ASSERT (LagestMmramRangeIndex < CurrentBlock->NumberOfMmReservedRegions);
//
// 2. Split the largest region and mark the allocated region as ALLOCATED
//
FullMmramRangeCount = CurrentBlock->NumberOfMmReservedRegions + 1;
NewDescriptorBlock = (EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *)BuildGuidHob (
&gEfiSmmSmramMemoryGuid,
sizeof (EFI_MMRAM_HOB_DESCRIPTOR_BLOCK) + ((FullMmramRangeCount - 1) * sizeof (EFI_MMRAM_DESCRIPTOR))
);
ASSERT (NewDescriptorBlock != NULL);
NewDescriptorBlock->NumberOfMmReservedRegions = FullMmramRangeCount;
FullMmramRanges = NewDescriptorBlock->Descriptor;
//
// Get current MMRAM descriptors and fill to the full MMRAM ranges
//
CopyMem (NewDescriptorBlock->Descriptor, CurrentBlock->Descriptor, CurrentBlock->NumberOfMmReservedRegions * sizeof (EFI_MMRAM_DESCRIPTOR));
Largest = &FullMmramRanges[LagestMmramRangeIndex];
ASSERT ((Largest->PhysicalSize & EFI_PAGE_MASK) == 0);
ASSERT (Largest->PhysicalSize > EFI_PAGES_TO_SIZE (Pages));
Allocated = &NewDescriptorBlock->Descriptor[NewDescriptorBlock->NumberOfMmReservedRegions - 1];
//
// Allocate MMRAM
//
Largest->PhysicalSize -= EFI_PAGES_TO_SIZE (Pages);
Allocated->CpuStart = Largest->CpuStart + Largest->PhysicalSize;
Allocated->PhysicalStart = Largest->PhysicalStart + Largest->PhysicalSize;
Allocated->RegionState = Largest->RegionState | EFI_ALLOCATED;
Allocated->PhysicalSize = EFI_PAGES_TO_SIZE (Pages);
//
// Scrub old one
//
ZeroMem (&MmramInfoHob->Name, sizeof (MmramInfoHob->Name));
//
// New MMRAM descriptor block
//
*NewBlock = NewDescriptorBlock;
return Allocated->CpuStart;
}
/**
Load the MM Core image into MMRAM and executes the MM Core from MMRAM.
@param[in] MmCommBuffer MM communicate buffer
@return EFI_STATUS Execute MM core successfully.
Other Execute MM core failed.
**/
EFI_STATUS
ExecuteMmCoreFromMmram (
IN MM_COMM_BUFFER *MmCommBuffer
)
{
EFI_STATUS Status;
UINTN PageCount;
VOID *MmHobList;
UINTN MmHobSize;
EFI_GUID MmCoreFileName;
UINTN MmFvSize;
EFI_PHYSICAL_ADDRESS MmFvBase;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
STANDALONE_MM_FOUNDATION_ENTRY_POINT Entry;
EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *Block;
MmFvBase = 0;
MmFvSize = 0;
//
// Search all Firmware Volumes for a PE/COFF image in a file of type MM_CORE_STANDALONE.
//
Status = LocateMmCoreFv (&MmFvBase, &MmFvSize, &MmCoreFileName, &ImageContext.Handle);
ASSERT_EFI_ERROR (Status);
//
// Initialize ImageContext
//
ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
//
// Get information about the image being loaded
//
Status = PeCoffLoaderGetImageInfo (&ImageContext);
if (EFI_ERROR (Status)) {
return Status;
}
PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
//
// Allocate memory for the image being loaded from unallocated mmram range
//
ImageContext.ImageAddress = MmIplAllocateMmramPage (PageCount, &Block);
if (ImageContext.ImageAddress == 0) {
return EFI_NOT_FOUND;
}
//
// Align buffer on section boundary
//
ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
//
// Print debug message showing MM Core load address.
//
DEBUG ((DEBUG_INFO, "StandaloneMM IPL loading MM Core at MMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
//
// Load the image to our new buffer
//
Status = PeCoffLoaderLoadImage (&ImageContext);
if (!EFI_ERROR (Status)) {
//
// Relocate the image in our new buffer
//
Status = PeCoffLoaderRelocateImage (&ImageContext);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "MmCoreImageBase - 0x%016lx\n", ImageContext.ImageAddress));
DEBUG ((DEBUG_INFO, "MmCoreImageSize - 0x%016lx\n", ImageContext.ImageSize));
//
// Flush the instruction cache so the image data are written before we execute it
//
InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
//
// Get HOB list for Standalone MM Core.
//
MmHobSize = 0;
MmHobList = CreatMmHobList (
&MmHobSize,
MmCommBuffer,
MmFvBase,
MmFvSize,
&MmCoreFileName,
ImageContext.ImageAddress,
ImageContext.ImageSize,
ImageContext.EntryPoint,
Block
);
//
// Print debug message showing Standalone MM Core entry point address.
//
DEBUG ((DEBUG_INFO, "StandaloneMM IPL calling Standalone MM Core at MMRAM address - 0x%016lx\n", ImageContext.EntryPoint));
//
// Execute image
//
Entry = (STANDALONE_MM_FOUNDATION_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;
Status = Entry (MmHobList);
ASSERT_EFI_ERROR (Status);
FreePages (MmHobList, EFI_SIZE_TO_PAGES (MmHobSize));
}
}
return Status;
}
/**
This is the callback function on end of PEI.
This callback is used for call MmEndOfPeiHandler in standalone MM core.
@param PeiServices General purpose services available to every PEIM.
@param NotifyDescriptor The notification structure this PEIM registered on install.
@param Ppi Pointer to the PPI data associated with this function.
@retval EFI_SUCCESS Exit boot services successfully.
@retval Other Exit boot services failed.
**/
EFI_STATUS
EFIAPI
EndOfPeiCallback (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
)
{
EFI_MM_COMMUNICATE_HEADER CommunicateHeader;
UINTN Size;
EFI_STATUS Status;
//
// Use Guid to initialize EFI_MM_COMMUNICATE_HEADER structure
//
CopyGuid (&CommunicateHeader.HeaderGuid, &gEfiMmEndOfPeiProtocol);
CommunicateHeader.MessageLength = 1;
CommunicateHeader.Data[0] = 0;
//
// Generate the Software SMI and return the result
//
Size = sizeof (CommunicateHeader);
Status = Communicate (NULL, &CommunicateHeader, &Size);
ASSERT_EFI_ERROR (Status);
return Status;
}
/**
Dispatch StandaloneMm drivers in MM.
StandaloneMm core will exit when MmEntryPoint was registered in CPU
StandaloneMm driver, and issue a software SMI by communicate mode to
dispatch other StandaloneMm drivers.
@retval EFI_SUCCESS Dispatch StandaloneMm drivers successfully.
@retval Other Dispatch StandaloneMm drivers failed.
**/
EFI_STATUS
MmIplDispatchMmDrivers (
VOID
)
{
EFI_STATUS Status;
UINTN Size;
EFI_MM_COMMUNICATE_HEADER CommunicateHeader;
//
// Use Guid to initialize EFI_MM_COMMUNICATE_HEADER structure
//
CopyGuid (&CommunicateHeader.HeaderGuid, &gEventMmDispatchGuid);
CommunicateHeader.MessageLength = 1;
CommunicateHeader.Data[0] = 0;
//
// Generate the Software SMI and return the result
//
Size = sizeof (CommunicateHeader);
Status = Communicate (NULL, &CommunicateHeader, &Size);
ASSERT_EFI_ERROR (Status);
return Status;
}
/**
Build communication buffer HOB.
@return MM_COMM_BUFFER Pointer of MM communication buffer
**/
MM_COMM_BUFFER *
MmIplBuildCommBufferHob (
VOID
)
{
EFI_STATUS Status;
MM_COMM_BUFFER *MmCommBuffer;
UINT64 MmCommBufferPages;
MmCommBufferPages = PcdGet32 (PcdMmCommBufferPages);
MmCommBuffer = BuildGuidHob (&gMmCommBufferHobGuid, sizeof (MM_COMM_BUFFER));
ASSERT (MmCommBuffer != NULL);
//
// Set MM communicate buffer size
//
MmCommBuffer->NumberOfPages = MmCommBufferPages;
//
// Allocate runtime memory for MM communicate buffer
//
MmCommBuffer->PhysicalStart = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages (MmCommBufferPages);
if (MmCommBuffer->PhysicalStart == 0) {
DEBUG ((DEBUG_ERROR, "Fail to allocate MM communication buffer\n"));
ASSERT (MmCommBuffer->PhysicalStart != 0);
}
//
// Build MM unblock memory region HOB for MM communication buffer
//
Status = MmUnblockMemoryRequest (MmCommBuffer->PhysicalStart, MmCommBufferPages);
ASSERT_EFI_ERROR (Status);
//
// Allocate runtime memory for MM communication status parameters :
// ReturnStatus, ReturnBufferSize, IsCommBufferValid
//
MmCommBuffer->Status = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimePages (EFI_SIZE_TO_PAGES (sizeof (MM_COMM_BUFFER_STATUS)));
if (MmCommBuffer->Status == 0) {
DEBUG ((DEBUG_ERROR, "Fail to allocate memory for MM communication status\n"));
ASSERT (MmCommBuffer->Status != 0);
}
//
// Build MM unblock memory region HOB for MM communication status
//
Status = MmUnblockMemoryRequest (MmCommBuffer->Status, EFI_SIZE_TO_PAGES (sizeof (MM_COMM_BUFFER_STATUS)));
ASSERT_EFI_ERROR (Status);
return MmCommBuffer;
}
/**
The Entry Point for MM IPL at PEI stage.
Load MM Core into MMRAM.
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS The entry point is executed successfully.
@retval Other Some error occurred when executing this entry point.
**/
EFI_STATUS
EFIAPI
StandaloneMmIplPeiEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
MM_COMM_BUFFER *MmCommBuffer;
//
// Build communication buffer HOB.
//
MmCommBuffer = MmIplBuildCommBufferHob ();
ASSERT (MmCommBuffer != NULL);
//
// Locate and execute Mm Core to dispatch MM drivers.
//
Status = ExecuteMmCoreFromMmram (MmCommBuffer);
ASSERT_EFI_ERROR (Status);
//
// Install MmCommunicationPpi
//
Status = PeiServicesInstallPpi (&mPpiList);
ASSERT_EFI_ERROR (Status);
//
// Create end of pei callback to call MmEndOfPeiHandler
//
Status = PeiServicesNotifyPpi (&mNotifyList);
ASSERT_EFI_ERROR (Status);
//
// Dispatch StandaloneMm drivers in MM
//
Status = MmIplDispatchMmDrivers ();
ASSERT_EFI_ERROR (Status);
return EFI_SUCCESS;
}