/** @file MM IPL that load the MM Core into MMRAM at PEI stage Copyright (c) 2024, Intel Corporation. All rights reserved.
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; // // 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; }