git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@581 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			499 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			499 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2006, Intel Corporation                                                         
 | |
| All rights reserved. This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
|                                                                                           
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| Module Name:
 | |
|   
 | |
|   MemoryStatusCode.c
 | |
|    
 | |
| Abstract:
 | |
| 
 | |
|   Lib to provide memory journal status code reporting Routines.
 | |
| 
 | |
| --*/
 | |
| #include "MemoryStatusCode.h"
 | |
| 
 | |
| //
 | |
| // Global variable.  Not accessible while running from flash.
 | |
| // After we relocate ourselves into memory, we update this
 | |
| // and use it to determine if we are running from flash or memory.
 | |
| //
 | |
| 
 | |
| //
 | |
| // Global variable used to replace the PPI once we start running from memory.
 | |
| //
 | |
| PEI_STATUS_CODE_MEMORY_PPI    mStatusCodeMemoryPpi = { 0, 0, 0, 0 };
 | |
| 
 | |
| //
 | |
| // PPI descriptor for the MonoStatusCode PEIM, see MonoStatusCode.c
 | |
| //
 | |
| extern EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode;
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MemoryStatusCodeInitialize (
 | |
|   IN EFI_FFS_FILE_HEADER       *FfsHeader,
 | |
|   IN EFI_PEI_SERVICES          **PeiServices
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Initialization routine.
 | |
|   Allocates heap space for storing Status Codes.
 | |
|   Installs a PPI to point to that heap space.
 | |
|   Installs a callback to switch to memory.
 | |
|   Installs a callback to 
 | |
| 
 | |
| Arguments: 
 | |
| 
 | |
|   FfsHeader   - FV this PEIM was loaded from.
 | |
|   PeiServices - General purpose services available to every PEIM.
 | |
| 
 | |
| Returns: 
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   MEMORY_STATUS_CODE_INSTANCE *PrivateData;
 | |
|   PEI_STATUS_CODE_MEMORY_PPI  *StatusCodeMemoryPpi;
 | |
|   EFI_PEI_PROGRESS_CODE_PPI   *ReportStatusCodePpi;
 | |
|   EFI_PHYSICAL_ADDRESS        Buffer;
 | |
|   VOID                        *StartPointer;
 | |
|   UINT32                      Length;
 | |
|   UINT32                      LastEntry;
 | |
|   EFI_PEI_PPI_DESCRIPTOR      *ReportStatusCodeDescriptor;
 | |
|   EFI_PEI_PPI_DESCRIPTOR      *StatusCodeMemoryDescriptor;
 | |
| 
 | |
|   //
 | |
|   // Determine if we are being called after relocation into memory.
 | |
|   //
 | |
|   if (!gRunningFromMemory) {
 | |
|     //
 | |
|     // If we are not running from memory, we need to allocate some heap and
 | |
|     // install the PPI
 | |
|     //
 | |
|     //
 | |
|     // Allocate heap storage for the journal
 | |
|     //
 | |
|     Status = (*PeiServices)->AllocatePool (
 | |
|                               PeiServices,
 | |
|                               PEI_STATUS_CODE_HEAP_LENGTH,
 | |
|                               &StartPointer
 | |
|                               );
 | |
| 
 | |
|     //
 | |
|     // This is not a required feature to boot.
 | |
|     //
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // Allocate heap storage for private data
 | |
|     // The private data contains the FFS header for this PEIM,
 | |
|     // a PPI containing information about the status code journal, and
 | |
|     // a notification for the LoadFile service, to relocate the PEIM into
 | |
|     // memory.
 | |
|     //
 | |
|     Status = (*PeiServices)->AllocatePool (
 | |
|                               PeiServices,
 | |
|                               sizeof (MEMORY_STATUS_CODE_INSTANCE),
 | |
|                               (VOID **) &PrivateData
 | |
|                               );
 | |
| 
 | |
|     //
 | |
|     // This is not a required feature to boot.
 | |
|     //
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // Update the contents of the private data.
 | |
|     //
 | |
|     PrivateData->Signature                      = MEMORY_STATUS_CODE_SIGNATURE;
 | |
|     PrivateData->This = PrivateData;
 | |
|     PrivateData->FfsHeader = FfsHeader;
 | |
|     PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
 | |
|     PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;
 | |
|     PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi;
 | |
|     PrivateData->StatusCodeMemoryPpi.FirstEntry = 0;
 | |
|     PrivateData->StatusCodeMemoryPpi.LastEntry = 0;
 | |
|     PrivateData->StatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPointer;
 | |
|     PrivateData->StatusCodeMemoryPpi.Length = PEI_STATUS_CODE_HEAP_LENGTH;
 | |
|     PrivateData->NotifyDescriptor.Flags =
 | |
|       (
 | |
|         EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
 | |
|         EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
 | |
|       );
 | |
|     PrivateData->NotifyDescriptor.Guid    = &gEfiPeiFvFileLoaderPpiGuid;
 | |
|     PrivateData->NotifyDescriptor.Notify  = LoadImageCallback;
 | |
| 
 | |
|     //
 | |
|     // Publish the PPI
 | |
|     //
 | |
|     Status = (*PeiServices)->InstallPpi (PeiServices, &PrivateData->PpiDescriptor);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // Post a callback to relocate to memory
 | |
|     //
 | |
|     Status = (**PeiServices).NotifyPpi (PeiServices, &PrivateData->NotifyDescriptor);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // If we are running from memory, we need to copy from the heap to a RT
 | |
|     // memory buffer.
 | |
|     //
 | |
|     //
 | |
|     // Locate Journal
 | |
|     //
 | |
|     Status = (*PeiServices)->LocatePpi (
 | |
|                               PeiServices,
 | |
|                               &gPeiStatusCodeMemoryPpiGuid,
 | |
|                               0,
 | |
|                               &StatusCodeMemoryDescriptor,
 | |
|                               (VOID **) &StatusCodeMemoryPpi
 | |
|                               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // Get private data
 | |
|     //
 | |
|     PrivateData = _CR (StatusCodeMemoryDescriptor, MEMORY_STATUS_CODE_INSTANCE, PpiDescriptor);
 | |
|     //
 | |
|     // At this point, we need to fix up any addresses that we have as the heap
 | |
|     // has moved.
 | |
|     //
 | |
|     PrivateData->PpiDescriptor.Ppi  = &PrivateData->StatusCodeMemoryPpi;
 | |
|     PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;
 | |
|     PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address +
 | |
|       (UINTN) PrivateData - (UINTN) PrivateData->This;
 | |
|     PrivateData->NotifyDescriptor.Guid    = &gEfiPeiFvFileLoaderPpiGuid;
 | |
|     PrivateData->NotifyDescriptor.Notify  = LoadImageCallback;
 | |
|     PrivateData->This                     = PrivateData;
 | |
| 
 | |
|     //
 | |
|     // Allocate RT memory.
 | |
|     //
 | |
|     Status = (*PeiServices)->AllocatePages (
 | |
|                               PeiServices,
 | |
|                               EfiRuntimeServicesData,
 | |
|                               PEI_STATUS_CODE_RT_PAGES,
 | |
|                               &Buffer
 | |
|                               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     DEBUG_CODE (
 | |
|       ZeroMem ((VOID *) (UINTN) Buffer, PEI_STATUS_CODE_RT_LENGTH);
 | |
|     );
 | |
| 
 | |
|     //
 | |
|     // Copy the heap to the allocated memory.
 | |
|     // Unwind the rolling queue to start at 0 in the new space.  We need to do
 | |
|     // this because the new queue is much bigger than the heap allocation.
 | |
|     //
 | |
|     if (PEI_STATUS_CODE_RT_LENGTH <= PEI_STATUS_CODE_HEAP_LENGTH) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     if (StatusCodeMemoryPpi->LastEntry >= StatusCodeMemoryPpi->FirstEntry) {
 | |
|       LastEntry = StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry;
 | |
|       StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY)));
 | |
|       Length = (StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry) * sizeof (EFI_STATUS_CODE_ENTRY);
 | |
|       (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length);
 | |
|     } else {
 | |
|       //
 | |
|       // The last entry will be the new last entry after moving heap to buffer
 | |
|       //
 | |
|       LastEntry = (PEI_STATUS_CODE_MAX_HEAP_ENTRY - StatusCodeMemoryPpi->FirstEntry) + StatusCodeMemoryPpi->LastEntry;
 | |
|       //
 | |
|       // Copy from the first entry to the end of the heap
 | |
|       //
 | |
|       StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY)));
 | |
|       Length = PEI_STATUS_CODE_HEAP_LENGTH - (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY));
 | |
|       (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length);
 | |
|       //
 | |
|       // Copy from the start to the heap to the last entry
 | |
|       //
 | |
|       StartPointer = (VOID *) (UINTN) StatusCodeMemoryPpi->Address;
 | |
|       (*PeiServices)->CopyMem (
 | |
|                         (VOID *) (UINTN) (Buffer + Length),
 | |
|                         StartPointer,
 | |
|                         (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY))
 | |
|                         );
 | |
|     };
 | |
| 
 | |
|     //
 | |
|     // Update the PPI to NULL, so it will not be used.
 | |
|     //
 | |
|     StatusCodeMemoryPpi->FirstEntry = 0;
 | |
|     StatusCodeMemoryPpi->LastEntry  = 0;
 | |
|     StatusCodeMemoryPpi->Address    = 0;
 | |
|     StatusCodeMemoryPpi->Length     = 0;
 | |
| 
 | |
|     //
 | |
|     // Update in memory version of PPI that will be used.
 | |
|     //
 | |
|     mStatusCodeMemoryPpi.FirstEntry = 0;
 | |
|     mStatusCodeMemoryPpi.LastEntry  = LastEntry;
 | |
|     mStatusCodeMemoryPpi.Address    = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer;
 | |
|     mStatusCodeMemoryPpi.Length     = PEI_STATUS_CODE_RT_LENGTH;
 | |
| 
 | |
|     //
 | |
|     // Reinstall the report status code function
 | |
|     //
 | |
|     //
 | |
|     // Locate status code PPI
 | |
|     //
 | |
|     Status = (*PeiServices)->LocatePpi (
 | |
|                               PeiServices,
 | |
|                               &gEfiPeiStatusCodePpiGuid,
 | |
|                               0,
 | |
|                               &ReportStatusCodeDescriptor,
 | |
|                               (VOID **) &ReportStatusCodePpi
 | |
|                               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // Reinstall the ReportStatusCode interface using the memory-based
 | |
|     // descriptor
 | |
|     //
 | |
|     Status = (*PeiServices)->ReInstallPpi (
 | |
|                               PeiServices,
 | |
|                               ReportStatusCodeDescriptor,
 | |
|                               &mPpiListStatusCode
 | |
|                               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       CpuBreakpoint ();
 | |
|       return Status;
 | |
|     }
 | |
|     //
 | |
|     // Publish a GUIDed HOB that contains a pointer to the status code PPI
 | |
|     // structure.  This is a bit of a short cut as I just used the PPI GUID to
 | |
|     // identify the HOB.  This HOB is caught by the DXE status code memory
 | |
|     // listener and used to find the journal.
 | |
|     //
 | |
|     StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;
 | |
| 
 | |
|     BuildGuidDataHob (
 | |
|       &gPeiStatusCodeMemoryPpiGuid,
 | |
|       &StatusCodeMemoryPpi,
 | |
|       sizeof (VOID *)
 | |
|       );
 | |
|   }
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| MemoryReportStatusCode (
 | |
|   IN EFI_STATUS_CODE_TYPE     CodeType,
 | |
|   IN EFI_STATUS_CODE_VALUE    Value,
 | |
|   IN UINT32                   Instance,
 | |
|   IN EFI_GUID                 * CallerId,
 | |
|   IN EFI_STATUS_CODE_DATA     * Data OPTIONAL
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Provide a memory status code
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Same as ReportStatusCode PPI
 | |
|     
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS   This function always returns success
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   PEI_STATUS_CODE_MEMORY_PPI  *StatusCodeMemoryPpi;
 | |
|   EFI_STATUS_CODE_ENTRY       *CurrentEntry;
 | |
|   UINT32                       LastEntry;
 | |
|   MEMORY_STATUS_CODE_INSTANCE *PrivateData;
 | |
|   EFI_PEI_PPI_DESCRIPTOR      *StatusCodeMemoryDescriptor;
 | |
|   EFI_PEI_SERVICES            **PeiServices;
 | |
| 
 | |
|   PeiServices = GetPeiServicesTablePointer ();
 | |
|   //
 | |
|   // We don't care to log debug codes.
 | |
|   //
 | |
|   if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (!gRunningFromMemory) {
 | |
|     //
 | |
|     // If we are called from DXE and have not been reinstalled into memory, we
 | |
|     // can no longer locate the journal, so we can no longer log status codes.
 | |
|     //
 | |
|     if (!PeiServices) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     //
 | |
|     // Locate Journal
 | |
|     //
 | |
|     Status = (*PeiServices)->LocatePpi (
 | |
|                               PeiServices,
 | |
|                               &gPeiStatusCodeMemoryPpiGuid,
 | |
|                               0,
 | |
|                               &StatusCodeMemoryDescriptor,
 | |
|                               (VOID **) &StatusCodeMemoryPpi
 | |
|                               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     //
 | |
|     // Determine the last entry in the journal.
 | |
|     // This is needed to properly implement the rolling queue.
 | |
|     //
 | |
|     LastEntry = PEI_STATUS_CODE_MAX_HEAP_ENTRY;
 | |
| 
 | |
|     //
 | |
|     // Get private data
 | |
|     //
 | |
|     PrivateData = _CR (StatusCodeMemoryDescriptor, MEMORY_STATUS_CODE_INSTANCE, PpiDescriptor);
 | |
| 
 | |
|     //
 | |
|     // Once memory gets installed, heap gets moved to real memory.
 | |
|     // We need to fix up the pointers to match the move.
 | |
|     //
 | |
|     PrivateData->PpiDescriptor.Ppi  = &PrivateData->StatusCodeMemoryPpi;
 | |
|     PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;
 | |
|     PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address +
 | |
|       (UINTN) PrivateData - (UINTN) PrivateData->This;
 | |
|     PrivateData->NotifyDescriptor.Guid    = &gEfiPeiFvFileLoaderPpiGuid;
 | |
|     PrivateData->NotifyDescriptor.Notify  = LoadImageCallback;
 | |
|     PrivateData->This                     = PrivateData;
 | |
| 
 | |
|     StatusCodeMemoryPpi                   = PrivateData->PpiDescriptor.Ppi;
 | |
|   } else {
 | |
|     //
 | |
|     // Use global/memory copy of the PPI
 | |
|     //
 | |
|     StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;
 | |
| 
 | |
|     //
 | |
|     // Determine the last entry in the journal.
 | |
|     // This is needed to properly implement the rolling queue.
 | |
|     //
 | |
|     LastEntry = PEI_STATUS_CODE_MAX_RT_ENTRY;
 | |
|   }
 | |
|   //
 | |
|   // Return if we are using a cleared PPI somehow
 | |
|   //
 | |
|   if (!StatusCodeMemoryPpi->Address || !StatusCodeMemoryPpi->Length) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   //
 | |
|   // Update the latest entry in the journal (may actually be first due to rolling
 | |
|   // queue).
 | |
|   //
 | |
|   CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY)));
 | |
| 
 | |
|   StatusCodeMemoryPpi->LastEntry = (StatusCodeMemoryPpi->LastEntry + 1) % LastEntry;
 | |
|   if (StatusCodeMemoryPpi->LastEntry == StatusCodeMemoryPpi->FirstEntry) {
 | |
|     StatusCodeMemoryPpi->FirstEntry = (StatusCodeMemoryPpi->FirstEntry + 1) % LastEntry;
 | |
|   }
 | |
| 
 | |
|   CurrentEntry->Type      = CodeType;
 | |
|   CurrentEntry->Value     = Value;
 | |
|   CurrentEntry->Instance  = Instance;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| LoadImageCallback (
 | |
|   IN EFI_PEI_SERVICES           **PeiServices,
 | |
|   IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,
 | |
|   IN VOID                       *Ppi
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Relocate the PEIM into memory.
 | |
| 
 | |
|   Once load protocol becomes available, relocate our PEIM into memory.
 | |
|   The primary benefit is to eliminate the blackout window that we would have in
 | |
|   the memory log between the end of PEI and the status code DXE driver taking
 | |
|   control.  If we don't do this, we cannot determine where our memory journal
 | |
|   is located and cannot function.
 | |
| 
 | |
|   A second benefit is speed optimization throughout DXE.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   PeiServices      - General purpose services available to every PEIM.
 | |
|   NotifyDescriptor - Information about the notify event.
 | |
|   Ppi              - Context
 | |
|     
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS   This function always returns success.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_PHYSICAL_ADDRESS        ImageAddress;
 | |
|   EFI_PHYSICAL_ADDRESS        EntryPoint;
 | |
|   UINT64                      ImageSize;
 | |
|   MEMORY_STATUS_CODE_INSTANCE *PrivateData;
 | |
| 
 | |
|   //
 | |
|   // Relocate to memory
 | |
|   //
 | |
|   if (!gRunningFromMemory) {
 | |
|     //
 | |
|     // Use the callback descriptor to get the FfsHeader
 | |
|     //
 | |
|     PrivateData = _CR (NotifyDescriptor, MEMORY_STATUS_CODE_INSTANCE, NotifyDescriptor);
 | |
| 
 | |
|     Status = ((EFI_PEI_FV_FILE_LOADER_PPI *) Ppi)->FvLoadFile (
 | |
|                                                     Ppi,
 | |
|                                                     PrivateData->FfsHeader,
 | |
|                                                     &ImageAddress,
 | |
|                                                     &ImageSize,
 | |
|                                                     &EntryPoint
 | |
|                                                     );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     //
 | |
|     // Set the flag in the loaded image that indicates the PEIM is executing
 | |
|     // from memory.
 | |
|     //
 | |
| #ifdef EFI_NT_EMULATOR
 | |
|     gRunningFromMemory = TRUE;
 | |
| #else
 | |
|     * (BOOLEAN *) ((UINTN) &gRunningFromMemory + (UINTN) EntryPoint - (UINTN) _ModuleEntryPoint) = TRUE;
 | |
| #endif
 | |
|     Status = ((EFI_PEIM_ENTRY_POINT )(UINTN) EntryPoint) (PrivateData->FfsHeader, PeiServices);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |