Home | History | Annotate | Download | only in DxeDebugPrintErrorLevelLib
      1 /** @file
      2   Debug Print Error Level library instance that provide compatibility with the
      3   "err" shell command.  This includes support for the Debug Mask Protocol
      4   supports for global debug print error level mask stored in an EFI Variable.
      5   This library instance only support DXE Phase modules.
      6 
      7   Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
      8   This program and the accompanying materials
      9   are licensed and made available under the terms and conditions of the BSD License
     10   which accompanies this distribution.  The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php.
     12 
     13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include <PiDxe.h>
     19 
     20 #include <Library/DebugPrintErrorLevelLib.h>
     21 #include <Library/PcdLib.h>
     22 #include <Library/HobLib.h>
     23 
     24 #include <Guid/DebugMask.h>
     25 
     26 ///
     27 /// Debug Mask Protocol function prototypes
     28 ///
     29 
     30 /**
     31   Retrieves the current debug print error level mask for a module are returns
     32   it in CurrentDebugMask.
     33 
     34   @param  This              The protocol instance pointer.
     35   @param  CurrentDebugMask  Pointer to the debug print error level mask that
     36                             is returned.
     37 
     38   @retval EFI_SUCCESS            The current debug print error level mask was
     39                                  returned in CurrentDebugMask.
     40   @retval EFI_INVALID_PARAMETER  CurrentDebugMask is NULL.
     41   @retval EFI_DEVICE_ERROR       The current debug print error level mask could
     42                                  not be retrieved.
     43 
     44 **/
     45 EFI_STATUS
     46 EFIAPI
     47 GetDebugMask (
     48   IN EFI_DEBUG_MASK_PROTOCOL  *This,
     49   IN OUT UINTN                *CurrentDebugMask
     50   );
     51 
     52 /**
     53   Sets the current debug print error level mask for a module to the value
     54   specified by NewDebugMask.
     55 
     56   @param  This          The protocol instance pointer.
     57   @param  NewDebugMask  The new debug print error level mask for this module.
     58 
     59   @retval EFI_SUCCESS            The current debug print error level mask was
     60                                  set to the value specified by NewDebugMask.
     61   @retval EFI_DEVICE_ERROR       The current debug print error level mask could
     62                                  not be set to the value specified by NewDebugMask.
     63 
     64 **/
     65 EFI_STATUS
     66 EFIAPI
     67 SetDebugMask (
     68   IN EFI_DEBUG_MASK_PROTOCOL  *This,
     69   IN UINTN                    NewDebugMask
     70   );
     71 
     72 ///
     73 /// Debug Mask Protocol instance
     74 ///
     75 EFI_DEBUG_MASK_PROTOCOL  mDebugMaskProtocol = {
     76   EFI_DEBUG_MASK_REVISION,
     77   GetDebugMask,
     78   SetDebugMask
     79 };
     80 
     81 ///
     82 /// Global variable that is set to TRUE after the first attempt is made to
     83 /// retrieve the global error level mask through the EFI Varibale Services.
     84 /// This variable prevents the EFI Variable Services from being called fort
     85 /// every DEBUG() macro.
     86 ///
     87 BOOLEAN           mGlobalErrorLevelInitialized = FALSE;
     88 
     89 ///
     90 /// Global variable that contains the current debug error level mask for the
     91 /// module that is using this library instance.  This variable is initially
     92 /// set to the PcdDebugPrintErrorLevel value.  If the EFI Variable exists that
     93 /// contains the global debug print error level mask, then that overrides the
     94 /// PcdDebugPrintErrorLevel value. The EFI Variable can optionally be
     95 /// discovered via a HOB so early DXE drivers can access the variable. If the
     96 /// Debug Mask Protocol SetDebugMask() service is called, then that overrides
     97 /// the PcdDebugPrintErrorLevel and the EFI Variable setting.
     98 ///
     99 UINT32            mDebugPrintErrorLevel        = 0;
    100 
    101 ///
    102 /// Global variable that is used to cache a pointer to the EFI System Table
    103 /// that is required to access the EFI Variable Services to get and set
    104 /// the global debug print error level mask value.  The UefiBootServicesTableLib
    105 /// is not used to prevent a circular dependency between these libraries.
    106 ///
    107 EFI_SYSTEM_TABLE  *mSystemTable                         = NULL;
    108 
    109 /**
    110   The constructor function caches the PCI Express Base Address and creates a
    111   Set Virtual Address Map event to convert physical address to virtual addresses.
    112 
    113   @param  ImageHandle   The firmware allocated handle for the EFI image.
    114   @param  SystemTable   A pointer to the EFI System Table.
    115 
    116   @retval EFI_SUCCESS   The constructor completed successfully.
    117   @retval Other value   The constructor did not complete successfully.
    118 
    119 **/
    120 EFI_STATUS
    121 EFIAPI
    122 DxeDebugPrintErrorLevelLibConstructor (
    123   IN EFI_HANDLE        ImageHandle,
    124   IN EFI_SYSTEM_TABLE  *SystemTable
    125   )
    126 {
    127   EFI_STATUS                  Status;
    128 
    129   //
    130   // Initialize the error level mask from PCD setting.
    131   //
    132   mDebugPrintErrorLevel = PcdGet32 (PcdDebugPrintErrorLevel);
    133 
    134   //
    135   // Install Debug Mask Protocol onto ImageHandle
    136   //
    137   mSystemTable = SystemTable;
    138   Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (
    139                                         &ImageHandle,
    140                                         &gEfiDebugMaskProtocolGuid, &mDebugMaskProtocol,
    141                                         NULL
    142                                         );
    143 
    144   //
    145   // Attempt to retrieve the global debug print error level mask from the EFI Variable
    146   // If the EFI Variable can not be accessed when this module's library constructors are
    147   // executed a HOB can be used to set the global debug print error level. If no value
    148   // was found then the EFI Variable access will be reattempted on every DEBUG() print
    149   // from this module until the EFI Variable services are available.
    150   //
    151   GetDebugPrintErrorLevel ();
    152 
    153   return Status;
    154 }
    155 
    156 /**
    157   The destructor function frees any allocated buffers and closes the Set Virtual
    158   Address Map event.
    159 
    160   @param  ImageHandle   The firmware allocated handle for the EFI image.
    161   @param  SystemTable   A pointer to the EFI System Table.
    162 
    163   @retval EFI_SUCCESS   The destructor completed successfully.
    164   @retval Other value   The destructor did not complete successfully.
    165 
    166 **/
    167 EFI_STATUS
    168 EFIAPI
    169 DxeDebugPrintErrorLevelLibDestructor (
    170   IN EFI_HANDLE        ImageHandle,
    171   IN EFI_SYSTEM_TABLE  *SystemTable
    172   )
    173 {
    174   //
    175   // Uninstall the Debug Mask Protocol from ImageHandle
    176   //
    177   return SystemTable->BootServices->UninstallMultipleProtocolInterfaces (
    178                                       ImageHandle,
    179                                       &gEfiDebugMaskProtocolGuid, &mDebugMaskProtocol,
    180                                       NULL
    181                                       );
    182 }
    183 
    184 /**
    185   Returns the debug print error level mask for the current module.
    186 
    187   @return  Debug print error level mask for the current module.
    188 
    189 **/
    190 UINT32
    191 EFIAPI
    192 GetDebugPrintErrorLevel (
    193   VOID
    194   )
    195 {
    196   EFI_STATUS  Status;
    197   EFI_TPL     CurrentTpl;
    198   UINTN       Size;
    199   UINTN       GlobalErrorLevel;
    200   VOID        *Hob;
    201 
    202   //
    203   // If the constructor has not been executed yet, then just return the PCD value.
    204   // This case should only occur if debug print is generated by a library
    205   // constructor for this module
    206   //
    207   if (mSystemTable == NULL) {
    208     return PcdGet32 (PcdDebugPrintErrorLevel);
    209   }
    210 
    211   //
    212   // Check to see if an attempt has been made to retrieve the global debug print
    213   // error level mask.  Since this library instance stores the global debug print
    214   // error level mask in an EFI Variable, the EFI Variable should only be accessed
    215   // once to reduce the overhead of reading the EFI Variable on every debug print
    216   //
    217   if (!mGlobalErrorLevelInitialized) {
    218     //
    219     // Make sure the TPL Level is low enough for EFI Variable Services to be called
    220     //
    221     CurrentTpl = mSystemTable->BootServices->RaiseTPL (TPL_HIGH_LEVEL);
    222     mSystemTable->BootServices->RestoreTPL (CurrentTpl);
    223     if (CurrentTpl <= TPL_CALLBACK) {
    224       //
    225       // Attempt to retrieve the global debug print error level mask from the
    226       // EFI Variable
    227       //
    228       Size = sizeof (GlobalErrorLevel);
    229       Status = mSystemTable->RuntimeServices->GetVariable (
    230                                        DEBUG_MASK_VARIABLE_NAME,
    231                                        &gEfiGenericVariableGuid,
    232                                        NULL,
    233                                        &Size,
    234                                        &GlobalErrorLevel
    235                                        );
    236       if (Status != EFI_NOT_AVAILABLE_YET) {
    237         //
    238         // If EFI Variable Services are available, then set a flag so the EFI
    239         // Variable will not be read again by this module.
    240         //
    241         mGlobalErrorLevelInitialized = TRUE;
    242         if (!EFI_ERROR (Status)) {
    243           //
    244           // If the EFI Varible exists, then set this module's module's mask to
    245           // the global debug print error level mask value.
    246           //
    247           mDebugPrintErrorLevel = (UINT32)GlobalErrorLevel;
    248         }
    249       } else {
    250         //
    251         // If variable services are not yet availible optionally get the global
    252         // debug print error level mask from a HOB.
    253         //
    254         Hob = GetFirstGuidHob (&gEfiGenericVariableGuid);
    255         if (Hob != NULL) {
    256           if (GET_GUID_HOB_DATA_SIZE (Hob) == sizeof (UINT32)) {
    257             mDebugPrintErrorLevel = *(UINT32 *)GET_GUID_HOB_DATA (Hob);
    258             mGlobalErrorLevelInitialized = TRUE;
    259           }
    260         }
    261       }
    262     }
    263   }
    264 
    265   //
    266   // Return the current mask value for this module.
    267   //
    268   return mDebugPrintErrorLevel;
    269 }
    270 
    271 /**
    272   Sets the global debug print error level mask fpr the entire platform.
    273 
    274   @param   ErrorLevel     Global debug print error level
    275 
    276   @retval  TRUE           The debug print error level mask was sucessfully set.
    277   @retval  FALSE          The debug print error level mask could not be set.
    278 
    279 **/
    280 BOOLEAN
    281 EFIAPI
    282 SetDebugPrintErrorLevel (
    283   UINT32  ErrorLevel
    284   )
    285 {
    286   EFI_STATUS  Status;
    287   EFI_TPL     CurrentTpl;
    288   UINTN       Size;
    289   UINTN       GlobalErrorLevel;
    290 
    291   //
    292   // Make sure the constructor has been executed
    293   //
    294   if (mSystemTable != NULL) {
    295     //
    296     // Make sure the TPL Level is low enough for EFI Variable Services
    297     //
    298     CurrentTpl = mSystemTable->BootServices->RaiseTPL (TPL_HIGH_LEVEL);
    299     mSystemTable->BootServices->RestoreTPL (CurrentTpl);
    300     if (CurrentTpl <= TPL_CALLBACK) {
    301       //
    302       // Attempt to store the global debug print error level mask in an EFI Variable
    303       //
    304       GlobalErrorLevel = (UINTN)ErrorLevel;
    305       Size = sizeof (GlobalErrorLevel);
    306       Status = mSystemTable->RuntimeServices->SetVariable (
    307                                        DEBUG_MASK_VARIABLE_NAME,
    308                                        &gEfiGenericVariableGuid,
    309                                        (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),
    310                                        Size,
    311                                        &GlobalErrorLevel
    312                                        );
    313       if (!EFI_ERROR (Status)) {
    314         //
    315         // If the EFI Variable was updated, then update the mask value for this
    316         // module and return TRUE.
    317         //
    318         mGlobalErrorLevelInitialized = TRUE;
    319         mDebugPrintErrorLevel = ErrorLevel;
    320         return TRUE;
    321       }
    322     }
    323   }
    324   //
    325   // Return FALSE since the EFI Variable could not be updated.
    326   //
    327   return FALSE;
    328 }
    329 
    330 /**
    331   Retrieves the current debug print error level mask for a module are returns
    332   it in CurrentDebugMask.
    333 
    334   @param  This              The protocol instance pointer.
    335   @param  CurrentDebugMask  Pointer to the debug print error level mask that
    336                             is returned.
    337 
    338   @retval EFI_SUCCESS            The current debug print error level mask was
    339                                  returned in CurrentDebugMask.
    340   @retval EFI_INVALID_PARAMETER  CurrentDebugMask is NULL.
    341   @retval EFI_DEVICE_ERROR       The current debug print error level mask could
    342                                  not be retrieved.
    343 
    344 **/
    345 EFI_STATUS
    346 EFIAPI
    347 GetDebugMask (
    348   IN EFI_DEBUG_MASK_PROTOCOL  *This,
    349   IN OUT UINTN                *CurrentDebugMask
    350   )
    351 {
    352   if (CurrentDebugMask == NULL) {
    353     return EFI_INVALID_PARAMETER;
    354   }
    355 
    356   //
    357   // Retrieve the current debug mask from mDebugPrintErrorLevel
    358   //
    359   *CurrentDebugMask = (UINTN)mDebugPrintErrorLevel;
    360   return EFI_SUCCESS;
    361 }
    362 
    363 /**
    364   Sets the current debug print error level mask for a module to the value
    365   specified by NewDebugMask.
    366 
    367   @param  This          The protocol instance pointer.
    368   @param  NewDebugMask  The new debug print error level mask for this module.
    369 
    370   @retval EFI_SUCCESS            The current debug print error level mask was
    371                                  set to the value specified by NewDebugMask.
    372   @retval EFI_DEVICE_ERROR       The current debug print error level mask could
    373                                  not be set to the value specified by NewDebugMask.
    374 
    375 **/
    376 EFI_STATUS
    377 EFIAPI
    378 SetDebugMask (
    379   IN EFI_DEBUG_MASK_PROTOCOL  *This,
    380   IN UINTN                    NewDebugMask
    381   )
    382 {
    383   //
    384   // Store the new debug mask into mDebugPrintErrorLevel
    385   //
    386   mDebugPrintErrorLevel = (UINT32)NewDebugMask;
    387   return EFI_SUCCESS;
    388 }
    389