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