1 /** @file
2   Base Debug library instance for QEMU debug port.
3   It uses PrintLib to send debug messages to a fixed I/O port.
4 
5   Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
6   Copyright (c) 2012, Red Hat, Inc.<BR>
7   SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include <Base.h>
12 #include <Library/DebugLib.h>
13 #include <Library/BaseLib.h>
14 #include <Library/IoLib.h>
15 #include <Library/PrintLib.h>
16 #include <Library/PcdLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/DebugPrintErrorLevelLib.h>
19 #include "DebugLibDetect.h"
20 
21 //
22 // Define the maximum debug and assert message length that this library supports
23 //
24 #define MAX_DEBUG_MESSAGE_LENGTH  0x100
25 
26 //
27 // VA_LIST can not initialize to NULL for all compiler, so we use this to
28 // indicate a null VA_LIST
29 //
30 VA_LIST     mVaListNull;
31 
32 /**
33   Prints a debug message to the debug output device if the specified error level is enabled.
34 
35   If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
36   GetDebugPrintErrorLevel (), then print the message specified by Format and the
37   associated variable argument list to the debug output device.
38 
39   If Format is NULL, then ASSERT().
40 
41   @param  ErrorLevel  The error level of the debug message.
42   @param  Format      Format string for the debug message to print.
43   @param  ...         Variable argument list whose contents are accessed
44                       based on the format string specified by Format.
45 
46 **/
47 VOID
48 EFIAPI
DebugPrint(IN UINTN ErrorLevel,IN CONST CHAR8 * Format,...)49 DebugPrint (
50   IN  UINTN        ErrorLevel,
51   IN  CONST CHAR8  *Format,
52   ...
53   )
54 {
55   VA_LIST         Marker;
56 
57   VA_START (Marker, Format);
58   DebugVPrint (ErrorLevel, Format, Marker);
59   VA_END (Marker);
60 }
61 
62 
63 /**
64   Prints a debug message to the debug output device if the specified
65   error level is enabled base on Null-terminated format string and a
66   VA_LIST argument list or a BASE_LIST argument list.
67 
68   If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
69   GetDebugPrintErrorLevel (), then print the message specified by Format and
70   the associated variable argument list to the debug output device.
71 
72   If Format is NULL, then ASSERT().
73 
74   @param  ErrorLevel      The error level of the debug message.
75   @param  Format          Format string for the debug message to print.
76   @param  VaListMarker    VA_LIST marker for the variable argument list.
77   @param  BaseListMarker  BASE_LIST marker for the variable argument list.
78 
79 **/
80 VOID
DebugPrintMarker(IN UINTN ErrorLevel,IN CONST CHAR8 * Format,IN VA_LIST VaListMarker,IN BASE_LIST BaseListMarker)81 DebugPrintMarker (
82   IN  UINTN         ErrorLevel,
83   IN  CONST CHAR8   *Format,
84   IN  VA_LIST       VaListMarker,
85   IN  BASE_LIST     BaseListMarker
86   )
87 {
88   CHAR8    Buffer[MAX_DEBUG_MESSAGE_LENGTH];
89   UINTN    Length;
90 
91   //
92   // If Format is NULL, then ASSERT().
93   //
94   ASSERT (Format != NULL);
95 
96   //
97   // Check if the global mask disables this message or the device is inactive
98   //
99   if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0 ||
100       !PlatformDebugLibIoPortFound ()) {
101     return;
102   }
103 
104   //
105   // Convert the DEBUG() message to an ASCII String
106   //
107   if (BaseListMarker == NULL) {
108     Length = AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker);
109   } else {
110     Length = AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker);
111   }
112 
113   //
114   // Send the print string to the debug I/O port
115   //
116   IoWriteFifo8 (PcdGet16 (PcdDebugIoPort), Length, Buffer);
117 }
118 
119 
120 /**
121   Prints a debug message to the debug output device if the specified
122   error level is enabled.
123 
124   If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
125   GetDebugPrintErrorLevel (), then print the message specified by Format and
126   the associated variable argument list to the debug output device.
127 
128   If Format is NULL, then ASSERT().
129 
130   @param  ErrorLevel    The error level of the debug message.
131   @param  Format        Format string for the debug message to print.
132   @param  VaListMarker  VA_LIST marker for the variable argument list.
133 
134 **/
135 VOID
136 EFIAPI
DebugVPrint(IN UINTN ErrorLevel,IN CONST CHAR8 * Format,IN VA_LIST VaListMarker)137 DebugVPrint (
138   IN  UINTN         ErrorLevel,
139   IN  CONST CHAR8   *Format,
140   IN  VA_LIST       VaListMarker
141   )
142 {
143   DebugPrintMarker (ErrorLevel, Format, VaListMarker, NULL);
144 }
145 
146 
147 /**
148   Prints a debug message to the debug output device if the specified
149   error level is enabled.
150   This function use BASE_LIST which would provide a more compatible
151   service than VA_LIST.
152 
153   If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
154   GetDebugPrintErrorLevel (), then print the message specified by Format and
155   the associated variable argument list to the debug output device.
156 
157   If Format is NULL, then ASSERT().
158 
159   @param  ErrorLevel      The error level of the debug message.
160   @param  Format          Format string for the debug message to print.
161   @param  BaseListMarker  BASE_LIST marker for the variable argument list.
162 
163 **/
164 VOID
165 EFIAPI
DebugBPrint(IN UINTN ErrorLevel,IN CONST CHAR8 * Format,IN BASE_LIST BaseListMarker)166 DebugBPrint (
167   IN  UINTN         ErrorLevel,
168   IN  CONST CHAR8   *Format,
169   IN  BASE_LIST     BaseListMarker
170   )
171 {
172   DebugPrintMarker (ErrorLevel, Format, mVaListNull, BaseListMarker);
173 }
174 
175 
176 /**
177   Prints an assert message containing a filename, line number, and description.
178   This may be followed by a breakpoint or a dead loop.
179 
180   Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
181   to the debug output device.  If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
182   PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if
183   DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then
184   CpuDeadLoop() is called.  If neither of these bits are set, then this function
185   returns immediately after the message is printed to the debug output device.
186   DebugAssert() must actively prevent recursion.  If DebugAssert() is called while
187   processing another DebugAssert(), then DebugAssert() must return immediately.
188 
189   If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
190   If Description is NULL, then a <Description> string of "(NULL) Description" is printed.
191 
192   @param  FileName     The pointer to the name of the source file that generated the assert condition.
193   @param  LineNumber   The line number in the source file that generated the assert condition
194   @param  Description  The pointer to the description of the assert condition.
195 
196 **/
197 VOID
198 EFIAPI
DebugAssert(IN CONST CHAR8 * FileName,IN UINTN LineNumber,IN CONST CHAR8 * Description)199 DebugAssert (
200   IN CONST CHAR8  *FileName,
201   IN UINTN        LineNumber,
202   IN CONST CHAR8  *Description
203   )
204 {
205   CHAR8  Buffer[MAX_DEBUG_MESSAGE_LENGTH];
206   UINTN  Length;
207 
208   //
209   // Generate the ASSERT() message in Ascii format
210   //
211   Length = AsciiSPrint (Buffer, sizeof Buffer, "ASSERT %a(%Lu): %a\n",
212              FileName, (UINT64)LineNumber, Description);
213 
214   //
215   // Send the print string to the debug I/O port, if present
216   //
217   if (PlatformDebugLibIoPortFound ()) {
218     IoWriteFifo8 (PcdGet16 (PcdDebugIoPort), Length, Buffer);
219   }
220 
221   //
222   // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
223   //
224   if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
225     CpuBreakpoint ();
226   } else if ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
227     CpuDeadLoop ();
228   }
229 }
230 
231 
232 /**
233   Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.
234 
235   This function fills Length bytes of Buffer with the value specified by
236   PcdDebugClearMemoryValue, and returns Buffer.
237 
238   If Buffer is NULL, then ASSERT().
239   If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
240 
241   @param   Buffer  The pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
242   @param   Length  The number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
243 
244   @return  Buffer  The pointer to the target buffer filled with PcdDebugClearMemoryValue.
245 
246 **/
247 VOID *
248 EFIAPI
DebugClearMemory(OUT VOID * Buffer,IN UINTN Length)249 DebugClearMemory (
250   OUT VOID  *Buffer,
251   IN UINTN  Length
252   )
253 {
254   //
255   // If Buffer is NULL, then ASSERT().
256   //
257   ASSERT (Buffer != NULL);
258 
259   //
260   // SetMem() checks for the the ASSERT() condition on Length and returns Buffer
261   //
262   return SetMem (Buffer, Length, PcdGet8(PcdDebugClearMemoryValue));
263 }
264 
265 
266 /**
267   Returns TRUE if ASSERT() macros are enabled.
268 
269   This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
270   PcdDebugProperyMask is set.  Otherwise FALSE is returned.
271 
272   @retval  TRUE    The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set.
273   @retval  FALSE   The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear.
274 
275 **/
276 BOOLEAN
277 EFIAPI
DebugAssertEnabled(VOID)278 DebugAssertEnabled (
279   VOID
280   )
281 {
282   return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
283 }
284 
285 
286 /**
287   Returns TRUE if DEBUG() macros are enabled.
288 
289   This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
290   PcdDebugProperyMask is set.  Otherwise FALSE is returned.
291 
292   @retval  TRUE    The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
293   @retval  FALSE   The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.
294 
295 **/
296 BOOLEAN
297 EFIAPI
DebugPrintEnabled(VOID)298 DebugPrintEnabled (
299   VOID
300   )
301 {
302   return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
303 }
304 
305 
306 /**
307   Returns TRUE if DEBUG_CODE() macros are enabled.
308 
309   This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
310   PcdDebugProperyMask is set.  Otherwise FALSE is returned.
311 
312   @retval  TRUE    The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set.
313   @retval  FALSE   The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear.
314 
315 **/
316 BOOLEAN
317 EFIAPI
DebugCodeEnabled(VOID)318 DebugCodeEnabled (
319   VOID
320   )
321 {
322   return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);
323 }
324 
325 
326 /**
327   Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.
328 
329   This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
330   PcdDebugProperyMask is set.  Otherwise FALSE is returned.
331 
332   @retval  TRUE    The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set.
333   @retval  FALSE   The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear.
334 
335 **/
336 BOOLEAN
337 EFIAPI
DebugClearMemoryEnabled(VOID)338 DebugClearMemoryEnabled (
339   VOID
340   )
341 {
342   return (BOOLEAN) ((PcdGet8(PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
343 }
344 
345 /**
346   Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel.
347 
348   This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel.
349 
350   @retval  TRUE    Current ErrorLevel is supported.
351   @retval  FALSE   Current ErrorLevel is not supported.
352 
353 **/
354 BOOLEAN
355 EFIAPI
DebugPrintLevelEnabled(IN CONST UINTN ErrorLevel)356 DebugPrintLevelEnabled (
357   IN  CONST UINTN        ErrorLevel
358   )
359 {
360   return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0);
361 }
362 
363 /**
364   Return the result of detecting the debug I/O port device.
365 
366   @retval TRUE   if the debug I/O port device was detected.
367   @retval FALSE  otherwise
368 
369 **/
370 BOOLEAN
371 EFIAPI
PlatformDebugLibIoPortDetect(VOID)372 PlatformDebugLibIoPortDetect (
373   VOID
374   )
375 {
376   return IoRead8 (PcdGet16 (PcdDebugIoPort)) == BOCHS_DEBUG_PORT_MAGIC;
377 }
378