/** @file | |
Debug Print Error Level library instance that provide compatibility with the | |
"err" shell command. This includes support for the Debug Mask Protocol | |
supports for global debug print error level mask stored in an EFI Variable. | |
This library instance only support DXE Phase modules. | |
Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <PiDxe.h> | |
#include <Library/DebugPrintErrorLevelLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/HobLib.h> | |
#include <Guid/DebugMask.h> | |
/// | |
/// Debug Mask Protocol function prototypes | |
/// | |
/** | |
Retrieves the current debug print error level mask for a module are returns | |
it in CurrentDebugMask. | |
@param This The protocol instance pointer. | |
@param CurrentDebugMask Pointer to the debug print error level mask that | |
is returned. | |
@retval EFI_SUCCESS The current debug print error level mask was | |
returned in CurrentDebugMask. | |
@retval EFI_INVALID_PARAMETER CurrentDebugMask is NULL. | |
@retval EFI_DEVICE_ERROR The current debug print error level mask could | |
not be retrieved. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
GetDebugMask ( | |
IN EFI_DEBUG_MASK_PROTOCOL *This, | |
IN OUT UINTN *CurrentDebugMask | |
); | |
/** | |
Sets the current debug print error level mask for a module to the value | |
specified by NewDebugMask. | |
@param This The protocol instance pointer. | |
@param NewDebugMask The new debug print error level mask for this module. | |
@retval EFI_SUCCESS The current debug print error level mask was | |
set to the value specified by NewDebugMask. | |
@retval EFI_DEVICE_ERROR The current debug print error level mask could | |
not be set to the value specified by NewDebugMask. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
SetDebugMask ( | |
IN EFI_DEBUG_MASK_PROTOCOL *This, | |
IN UINTN NewDebugMask | |
); | |
/// | |
/// Debug Mask Protocol instance | |
/// | |
EFI_DEBUG_MASK_PROTOCOL mDebugMaskProtocol = { | |
EFI_DEBUG_MASK_REVISION, | |
GetDebugMask, | |
SetDebugMask | |
}; | |
/// | |
/// Global variable that is set to TRUE after the first attempt is made to | |
/// retrieve the global error level mask through the EFI Varibale Services. | |
/// This variable prevents the EFI Variable Services from being called fort | |
/// every DEBUG() macro. | |
/// | |
BOOLEAN mGlobalErrorLevelInitialized = FALSE; | |
/// | |
/// Global variable that contains the current debug error level mask for the | |
/// module that is using this library instance. This variable is initially | |
/// set to the PcdDebugPrintErrorLevel value. If the EFI Variable exists that | |
/// contains the global debug print error level mask, then that overrides the | |
/// PcdDebugPrintErrorLevel value. The EFI Variable can optionally be | |
/// discovered via a HOB so early DXE drivers can access the variable. If the | |
/// Debug Mask Protocol SetDebugMask() service is called, then that overrides | |
/// the PcdDebugPrintErrorLevel and the EFI Variable setting. | |
/// | |
UINT32 mDebugPrintErrorLevel = 0; | |
/// | |
/// Global variable that is used to cache a pointer to the EFI System Table | |
/// that is required to access the EFI Variable Services to get and set | |
/// the global debug print error level mask value. The UefiBootServicesTableLib | |
/// is not used to prevent a circular dependency between these libraries. | |
/// | |
EFI_SYSTEM_TABLE *mSystemTable = NULL; | |
/** | |
The constructor function caches the PCI Express Base Address and creates a | |
Set Virtual Address Map event to convert physical address to virtual addresses. | |
@param ImageHandle The firmware allocated handle for the EFI image. | |
@param SystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The constructor completed successfully. | |
@retval Other value The constructor did not complete successfully. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DxeDebugPrintErrorLevelLibConstructor ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Initialize the error level mask from PCD setting. | |
// | |
mDebugPrintErrorLevel = PcdGet32 (PcdDebugPrintErrorLevel); | |
// | |
// Install Debug Mask Protocol onto ImageHandle | |
// | |
mSystemTable = SystemTable; | |
Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces ( | |
&ImageHandle, | |
&gEfiDebugMaskProtocolGuid, | |
&mDebugMaskProtocol, | |
NULL | |
); | |
// | |
// Attempt to retrieve the global debug print error level mask from the EFI Variable | |
// If the EFI Variable can not be accessed when this module's library constructors are | |
// executed a HOB can be used to set the global debug print error level. If no value | |
// was found then the EFI Variable access will be reattempted on every DEBUG() print | |
// from this module until the EFI Variable services are available. | |
// | |
GetDebugPrintErrorLevel (); | |
return Status; | |
} | |
/** | |
The destructor function frees any allocated buffers and closes the Set Virtual | |
Address Map event. | |
@param ImageHandle The firmware allocated handle for the EFI image. | |
@param SystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The destructor completed successfully. | |
@retval Other value The destructor did not complete successfully. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
DxeDebugPrintErrorLevelLibDestructor ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
// | |
// Uninstall the Debug Mask Protocol from ImageHandle | |
// | |
return SystemTable->BootServices->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDebugMaskProtocolGuid, | |
&mDebugMaskProtocol, | |
NULL | |
); | |
} | |
/** | |
Returns the debug print error level mask for the current module. | |
@return Debug print error level mask for the current module. | |
**/ | |
UINT32 | |
EFIAPI | |
GetDebugPrintErrorLevel ( | |
VOID | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_TPL CurrentTpl; | |
UINTN Size; | |
UINTN GlobalErrorLevel; | |
VOID *Hob; | |
// | |
// If the constructor has not been executed yet, then just return the PCD value. | |
// This case should only occur if debug print is generated by a library | |
// constructor for this module | |
// | |
if (mSystemTable == NULL) { | |
return PcdGet32 (PcdDebugPrintErrorLevel); | |
} | |
// | |
// Check to see if an attempt has been made to retrieve the global debug print | |
// error level mask. Since this library instance stores the global debug print | |
// error level mask in an EFI Variable, the EFI Variable should only be accessed | |
// once to reduce the overhead of reading the EFI Variable on every debug print | |
// | |
if (!mGlobalErrorLevelInitialized) { | |
// | |
// Make sure the TPL Level is low enough for EFI Variable Services to be called | |
// | |
CurrentTpl = mSystemTable->BootServices->RaiseTPL (TPL_HIGH_LEVEL); | |
mSystemTable->BootServices->RestoreTPL (CurrentTpl); | |
if (CurrentTpl <= TPL_CALLBACK) { | |
// | |
// Attempt to retrieve the global debug print error level mask from the | |
// EFI Variable | |
// | |
Size = sizeof (GlobalErrorLevel); | |
Status = mSystemTable->RuntimeServices->GetVariable ( | |
DEBUG_MASK_VARIABLE_NAME, | |
&gEfiGenericVariableGuid, | |
NULL, | |
&Size, | |
&GlobalErrorLevel | |
); | |
if (Status != EFI_NOT_AVAILABLE_YET) { | |
// | |
// If EFI Variable Services are available, then set a flag so the EFI | |
// Variable will not be read again by this module. | |
// | |
mGlobalErrorLevelInitialized = TRUE; | |
if (!EFI_ERROR (Status)) { | |
// | |
// If the EFI Varible exists, then set this module's module's mask to | |
// the global debug print error level mask value. | |
// | |
mDebugPrintErrorLevel = (UINT32)GlobalErrorLevel; | |
} | |
} else { | |
// | |
// If variable services are not yet available optionally get the global | |
// debug print error level mask from a HOB. | |
// | |
Hob = GetFirstGuidHob (&gEfiGenericVariableGuid); | |
if (Hob != NULL) { | |
if (GET_GUID_HOB_DATA_SIZE (Hob) == sizeof (UINT32)) { | |
mDebugPrintErrorLevel = *(UINT32 *)GET_GUID_HOB_DATA (Hob); | |
mGlobalErrorLevelInitialized = TRUE; | |
} | |
} | |
} | |
} | |
} | |
// | |
// Return the current mask value for this module. | |
// | |
return mDebugPrintErrorLevel; | |
} | |
/** | |
Sets the global debug print error level mask fpr the entire platform. | |
@param ErrorLevel Global debug print error level | |
@retval TRUE The debug print error level mask was sucessfully set. | |
@retval FALSE The debug print error level mask could not be set. | |
**/ | |
BOOLEAN | |
EFIAPI | |
SetDebugPrintErrorLevel ( | |
UINT32 ErrorLevel | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_TPL CurrentTpl; | |
UINTN Size; | |
UINTN GlobalErrorLevel; | |
// | |
// Make sure the constructor has been executed | |
// | |
if (mSystemTable != NULL) { | |
// | |
// Make sure the TPL Level is low enough for EFI Variable Services | |
// | |
CurrentTpl = mSystemTable->BootServices->RaiseTPL (TPL_HIGH_LEVEL); | |
mSystemTable->BootServices->RestoreTPL (CurrentTpl); | |
if (CurrentTpl <= TPL_CALLBACK) { | |
// | |
// Attempt to store the global debug print error level mask in an EFI Variable | |
// | |
GlobalErrorLevel = (UINTN)ErrorLevel; | |
Size = sizeof (GlobalErrorLevel); | |
Status = mSystemTable->RuntimeServices->SetVariable ( | |
DEBUG_MASK_VARIABLE_NAME, | |
&gEfiGenericVariableGuid, | |
(EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS), | |
Size, | |
&GlobalErrorLevel | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// If the EFI Variable was updated, then update the mask value for this | |
// module and return TRUE. | |
// | |
mGlobalErrorLevelInitialized = TRUE; | |
mDebugPrintErrorLevel = ErrorLevel; | |
return TRUE; | |
} | |
} | |
} | |
// | |
// Return FALSE since the EFI Variable could not be updated. | |
// | |
return FALSE; | |
} | |
/** | |
Retrieves the current debug print error level mask for a module are returns | |
it in CurrentDebugMask. | |
@param This The protocol instance pointer. | |
@param CurrentDebugMask Pointer to the debug print error level mask that | |
is returned. | |
@retval EFI_SUCCESS The current debug print error level mask was | |
returned in CurrentDebugMask. | |
@retval EFI_INVALID_PARAMETER CurrentDebugMask is NULL. | |
@retval EFI_DEVICE_ERROR The current debug print error level mask could | |
not be retrieved. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
GetDebugMask ( | |
IN EFI_DEBUG_MASK_PROTOCOL *This, | |
IN OUT UINTN *CurrentDebugMask | |
) | |
{ | |
if (CurrentDebugMask == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Retrieve the current debug mask from mDebugPrintErrorLevel | |
// | |
*CurrentDebugMask = (UINTN)mDebugPrintErrorLevel; | |
return EFI_SUCCESS; | |
} | |
/** | |
Sets the current debug print error level mask for a module to the value | |
specified by NewDebugMask. | |
@param This The protocol instance pointer. | |
@param NewDebugMask The new debug print error level mask for this module. | |
@retval EFI_SUCCESS The current debug print error level mask was | |
set to the value specified by NewDebugMask. | |
@retval EFI_DEVICE_ERROR The current debug print error level mask could | |
not be set to the value specified by NewDebugMask. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
SetDebugMask ( | |
IN EFI_DEBUG_MASK_PROTOCOL *This, | |
IN UINTN NewDebugMask | |
) | |
{ | |
// | |
// Store the new debug mask into mDebugPrintErrorLevel | |
// | |
mDebugPrintErrorLevel = (UINT32)NewDebugMask; | |
return EFI_SUCCESS; | |
} |