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