git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12072 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			336 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Library constructor & destructor, event handlers, and other internal worker functions.
 | |
| 
 | |
|   Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 | |
|   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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "ReportStatusCodeLibInternal.h"
 | |
| 
 | |
| EFI_EVENT                     mVirtualAddressChangeEvent;
 | |
| EFI_EVENT                     mExitBootServicesEvent;
 | |
| EFI_STATUS_CODE_DATA          *mStatusCodeData;
 | |
| BOOLEAN                       mInSmm;
 | |
| EFI_SMM_BASE_PROTOCOL         *mSmmBase;
 | |
| EFI_RUNTIME_SERVICES          *mInternalRT;
 | |
| BOOLEAN                       mHaveExitedBootServices = FALSE;
 | |
| EFI_REPORT_STATUS_CODE        mReportStatusCode = NULL;
 | |
| EFI_SMM_STATUS_CODE_PROTOCOL  *mSmmStatusCodeProtocol;
 | |
| 
 | |
| /**
 | |
|   Locates and caches SMM Status Code Protocol.
 | |
|  
 | |
| **/
 | |
| VOID
 | |
| SmmStatusCodeInitialize (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS Status;
 | |
| 
 | |
|   Status = gBS->LocateProtocol (&gEfiSmmStatusCodeProtocolGuid, NULL, (VOID **) &mSmmStatusCodeProtocol);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     mSmmStatusCodeProtocol = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Report status code via SMM Status Code Protocol.
 | |
|  
 | |
|   @param  Type          Indicates the type of status code being reported.
 | |
|   @param  Value         Describes the current status of a hardware or software entity.  
 | |
|                         This included information about the class and subclass that is used to classify the entity 
 | |
|                         as well as an operation.  For progress codes, the operation is the current activity. 
 | |
|                         For error codes, it is the exception.  For debug codes, it is not defined at this time. 
 | |
|   @param  Instance      The enumeration of a hardware or software entity within the system.  
 | |
|                         A system may contain multiple entities that match a class/subclass pairing. 
 | |
|                         The instance differentiates between them.  An instance of 0 indicates that instance information is unavailable, 
 | |
|                         not meaningful, or not relevant.  Valid instance numbers start with 1.
 | |
|   @param  CallerId      This optional parameter may be used to identify the caller. 
 | |
|                         This parameter allows the status code driver to apply different rules to different callers. 
 | |
|   @param  Data          This optional parameter may be used to pass additional data
 | |
|  
 | |
|   @retval EFI_SUCCESS   Always return EFI_SUCCESS.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SmmStatusCodeReport (
 | |
|   IN EFI_STATUS_CODE_TYPE     Type,
 | |
|   IN EFI_STATUS_CODE_VALUE    Value,
 | |
|   IN UINT32                   Instance,
 | |
|   IN EFI_GUID                 *CallerId OPTIONAL,
 | |
|   IN EFI_STATUS_CODE_DATA     *Data     OPTIONAL
 | |
|   )
 | |
| {
 | |
|   if (mSmmStatusCodeProtocol != NULL) {
 | |
|     (mSmmStatusCodeProtocol->ReportStatusCode) (mSmmStatusCodeProtocol, Type, Value, Instance, CallerId, Data);
 | |
|   }
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Locate the report status code service.
 | |
| 
 | |
|   In SMM, it tries to retrieve SMM Status Code Protocol.
 | |
|   Otherwise, it first tries to retrieve ReportStatusCode() in Runtime Services Table.
 | |
|   If not found, it then tries to retrieve ReportStatusCode() API of Report Status Code Protocol.
 | |
| 
 | |
|   @return   Function pointer to the report status code service.
 | |
|             NULL is returned if no status code service is available.
 | |
| 
 | |
| **/
 | |
| EFI_REPORT_STATUS_CODE
 | |
| InternalGetReportStatusCode (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS_CODE_PROTOCOL  *StatusCodeProtocol;
 | |
|   EFI_STATUS                Status;
 | |
| 
 | |
|   if (mInSmm) {
 | |
|     return (EFI_REPORT_STATUS_CODE) SmmStatusCodeReport;
 | |
|   } else if (mInternalRT != NULL && mInternalRT->Hdr.Revision < 0x20000) {
 | |
|     return ((FRAMEWORK_EFI_RUNTIME_SERVICES*)mInternalRT)->ReportStatusCode;
 | |
|   } else if (!mHaveExitedBootServices) {
 | |
|   	//
 | |
|   	// Check gBS just in case. ReportStatusCode is called before gBS is initialized.
 | |
|   	//
 | |
|     if (gBS != NULL) {
 | |
|       Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**)&StatusCodeProtocol);
 | |
|       if (!EFI_ERROR (Status) && StatusCodeProtocol != NULL) {
 | |
|         return StatusCodeProtocol->ReportStatusCode;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Internal worker function that reports a status code through the status code service.
 | |
| 
 | |
|   If status code service is not cached, then this function checks if status code service is
 | |
|   available in system.  If status code service is not available, then EFI_UNSUPPORTED is
 | |
|   returned.  If status code service is present, then it is cached in mReportStatusCode.
 | |
|   Finally this function reports status code through the status code service.
 | |
| 
 | |
|   @param  Type              Status code type.
 | |
|   @param  Value             Status code value.
 | |
|   @param  Instance          Status code instance number.
 | |
|   @param  CallerId          Pointer to a GUID that identifies the caller of this
 | |
|                             function.  This is an optional parameter that may be
 | |
|                             NULL.
 | |
|   @param  Data              Pointer to the extended data buffer.  This is an
 | |
|                             optional parameter that may be NULL.
 | |
| 
 | |
|   @retval EFI_SUCCESS       The status code was reported.
 | |
|   @retval EFI_UNSUPPORTED   Status code service is not available.
 | |
|   @retval EFI_UNSUPPORTED   Status code type is not supported.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| InternalReportStatusCode (
 | |
|   IN EFI_STATUS_CODE_TYPE     Type,
 | |
|   IN EFI_STATUS_CODE_VALUE    Value,
 | |
|   IN UINT32                   Instance,
 | |
|   IN CONST EFI_GUID           *CallerId OPTIONAL,
 | |
|   IN EFI_STATUS_CODE_DATA     *Data     OPTIONAL
 | |
|   )
 | |
| {
 | |
|   if ((ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
 | |
|       (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ||
 | |
|       (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)) {
 | |
|     //
 | |
|     // If mReportStatusCode is NULL, then check if status code service is available in system.
 | |
|     //
 | |
|     if (mReportStatusCode == NULL) {
 | |
|       mReportStatusCode = InternalGetReportStatusCode ();
 | |
|       if (mReportStatusCode == NULL) {
 | |
|         return EFI_UNSUPPORTED;
 | |
|       }
 | |
|     }
 | |
|   
 | |
|     //
 | |
|     // A status code service is present in system, so pass in all the parameters to the service.
 | |
|     //
 | |
|     return (*mReportStatusCode) (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
 | |
|   }
 | |
|   
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
 | |
| 
 | |
|   @param  Event        Event whose notification function is being invoked.
 | |
|   @param  Context      Pointer to the notification function's context
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ReportStatusCodeLibVirtualAddressChange (
 | |
|   IN EFI_EVENT        Event,
 | |
|   IN VOID             *Context
 | |
|   )
 | |
| {
 | |
|   if (mReportStatusCode != NULL) {
 | |
|     mInternalRT->ConvertPointer (0, (VOID **) &mReportStatusCode);
 | |
|   }
 | |
|   mInternalRT->ConvertPointer (0, (VOID **) &mStatusCodeData);
 | |
|   mInternalRT->ConvertPointer (0, (VOID **) &mInternalRT);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Notification function of EVT_SIGNAL_EXIT_BOOT_SERVICES.
 | |
| 
 | |
|   @param  Event        Event whose notification function is being invoked.
 | |
|   @param  Context      Pointer to the notification function's context
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| ReportStatusCodeLibExitBootServices (
 | |
|   IN EFI_EVENT        Event,
 | |
|   IN VOID             *Context
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // If mReportStatusCode is NULL, then see if a Status Code Protocol instance is present
 | |
|   // in the handle database.
 | |
|   //
 | |
|   if (mReportStatusCode == NULL) {
 | |
|     mReportStatusCode = InternalGetReportStatusCode ();
 | |
|   }
 | |
| 
 | |
|   mHaveExitedBootServices = TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The constructor function of SMM Runtime DXE Report Status Code Lib.
 | |
| 
 | |
|   This function allocates memory for extended status code data, caches
 | |
|   the report status code service, and registers events.
 | |
| 
 | |
|   @param  ImageHandle   The firmware allocated handle for the EFI image.
 | |
|   @param  SystemTable   A pointer to the EFI System Table.
 | |
|   
 | |
|   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ReportStatusCodeLibConstruct (
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
| 
 | |
|   //
 | |
|   // If in SMM mode, then allocates memory from SMRAM for extended status code data.
 | |
|   //
 | |
|   Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &mSmmBase);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     mSmmBase->InSmm (mSmmBase, &mInSmm);
 | |
|     if (mInSmm) {
 | |
|       Status = mSmmBase->SmmAllocatePool (
 | |
|                            mSmmBase,
 | |
|                            EfiRuntimeServicesData, 
 | |
|                            sizeof (EFI_STATUS_CODE_DATA) + EFI_STATUS_CODE_DATA_MAX_SIZE, 
 | |
|                            (VOID **) &mStatusCodeData
 | |
|                            );
 | |
|       ASSERT_EFI_ERROR (Status);
 | |
|       SmmStatusCodeInitialize ();
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // If not in SMM mode, then allocate runtime memory for extended status code data.
 | |
|   //
 | |
|   // Library should not use the gRT directly, for it may be converted by other library instance.
 | |
|   // 
 | |
|   mInternalRT = gRT;
 | |
|   mInSmm      = FALSE;
 | |
| 
 | |
|   mStatusCodeData = AllocateRuntimePool (sizeof (EFI_STATUS_CODE_DATA) + EFI_STATUS_CODE_DATA_MAX_SIZE);
 | |
|   ASSERT (mStatusCodeData != NULL);
 | |
|   //
 | |
|   // Cache the report status code service
 | |
|   // 
 | |
|   mReportStatusCode = InternalGetReportStatusCode ();
 | |
| 
 | |
|   //
 | |
|   // Register notify function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
 | |
|   // 
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   ReportStatusCodeLibVirtualAddressChange,
 | |
|                   NULL,
 | |
|                   &gEfiEventVirtualAddressChangeGuid,
 | |
|                   &mVirtualAddressChangeEvent
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Register notify function for EVT_SIGNAL_EXIT_BOOT_SERVICES
 | |
|   // 
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   ReportStatusCodeLibExitBootServices,
 | |
|                   NULL,
 | |
|                   &gEfiEventExitBootServicesGuid,
 | |
|                   &mExitBootServicesEvent
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The destructor function of SMM Runtime DXE Report Status Code Lib.
 | |
|   
 | |
|   The destructor function frees memory allocated by constructor, and closes related events.
 | |
|   It will ASSERT() if that related operation fails and it will always return EFI_SUCCESS. 
 | |
| 
 | |
|   @param  ImageHandle   The firmware allocated handle for the EFI image.
 | |
|   @param  SystemTable   A pointer to the EFI System Table.
 | |
|   
 | |
|   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ReportStatusCodeLibDestruct (
 | |
|   IN EFI_HANDLE        ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE  *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   if (!mInSmm) {
 | |
|     ASSERT (gBS != NULL);
 | |
|     Status = gBS->CloseEvent (mVirtualAddressChangeEvent);
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|     Status = gBS->CloseEvent (mExitBootServicesEvent);
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|     FreePool (mStatusCodeData);
 | |
|   } else {
 | |
|     mSmmBase->SmmFreePool (mSmmBase, mStatusCodeData);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 |