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