]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c
clean-up the license to open source.
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / PeiDxeDebugLibReportStatusCode / DebugLib.c
CommitLineData
2287f237 1/** @file\r
9ba6cd30 2 Debug Library based on report status code library.\r
2287f237 3\r
9ba6cd30 4 Copyright (c) 2006 - 2009, Intel Corporation<BR>\r
2287f237 5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
2287f237 15#include <FrameworkPei.h>\r
79bc7a89 16\r
2287f237 17#include <Guid/StatusCodeDataTypeId.h>\r
3a6064fa 18#include <Guid/StatusCodeDataTypeDebug.h>\r
2287f237 19\r
20#include <Library/DebugLib.h>\r
21#include <Library/BaseLib.h>\r
22#include <Library/BaseMemoryLib.h>\r
23#include <Library/ReportStatusCodeLib.h>\r
24#include <Library/PcdLib.h>\r
25\r
2287f237 26/**\r
2287f237 27 Prints a debug message to the debug output device if the specified error level is enabled.\r
28\r
9ba6cd30 29 If any bit in ErrorLevel is also set in PcdDebugPrintErrorLevel, then print \r
30 the message specified by Format and the associated variable argument list to \r
2287f237 31 the debug output device.\r
32\r
33 If Format is NULL, then ASSERT().\r
34\r
35 @param ErrorLevel The error level of the debug message.\r
36 @param Format Format string for the debug message to print.\r
967c09fa 37 @param ... Variable argument list whose contents are accessed \r
38 based on the format string specified by Format.\r
2287f237 39\r
40**/\r
41VOID\r
42EFIAPI\r
43DebugPrint (\r
44 IN UINTN ErrorLevel,\r
45 IN CONST CHAR8 *Format,\r
46 ...\r
47 )\r
48{\r
6916d99c 49 UINT64 Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1];\r
2287f237 50 EFI_DEBUG_INFO *DebugInfo;\r
51 UINTN TotalSize;\r
ca9938b8 52 VA_LIST VaListMarker;\r
53 BASE_LIST BaseListMarker;\r
54 CHAR8 *FormatString;\r
55 BOOLEAN Long;\r
2287f237 56\r
57 //\r
58 // If Format is NULL, then ASSERT().\r
59 //\r
60 ASSERT (Format != NULL);\r
61\r
62 //\r
63 // Check driver Debug Level value and global debug level\r
64 //\r
9ba6cd30 65 if ((ErrorLevel & PcdGet32 (PcdDebugPrintErrorLevel)) == 0) {\r
2287f237 66 return;\r
67 }\r
68\r
ca9938b8 69 //\r
0fac539f 70 // Compute the total size of the record.\r
71 // Note that the passing-in format string and variable parameters will be constructed to \r
72 // the following layout:\r
ca9938b8 73 //\r
0fac539f 74 // Buffer->|------------------------|\r
3d747a89 75 // | Padding | 4 bytes\r
0fac539f 76 // DebugInfo->|------------------------|\r
77 // | EFI_DEBUG_INFO | sizeof(EFI_DEBUG_INFO)\r
78 // BaseListMarker->|------------------------|\r
79 // | ... |\r
80 // | variable arguments | 12 * sizeof (UINT64)\r
81 // | ... |\r
82 // |------------------------|\r
83 // | Format String |\r
84 // |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer)\r
85 //\r
86 TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format);\r
ca9938b8 87\r
ca9938b8 88 //\r
89 // If the TotalSize is larger than the maximum record size, then return\r
90 //\r
1ca88083 91 if (TotalSize > sizeof (Buffer)) {\r
2287f237 92 return;\r
93 }\r
94\r
95 //\r
ca9938b8 96 // Fill in EFI_DEBUG_INFO\r
2287f237 97 //\r
9ba6cd30 98 // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarker is\r
99 // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarker will cause\r
100 // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO))\r
3d747a89 101 // just makes address of BaseListMarker, which follows DebugInfo, 64-bit aligned.\r
9ba6cd30 102 //\r
6916d99c 103 DebugInfo = (EFI_DEBUG_INFO *)(Buffer) + 1;\r
2287f237 104 DebugInfo->ErrorLevel = (UINT32)ErrorLevel;\r
ca9938b8 105 BaseListMarker = (BASE_LIST)(DebugInfo + 1);\r
3d7dfb38 106 FormatString = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12);\r
ca9938b8 107\r
108 //\r
109 // Copy the Format string into the record\r
110 //\r
111 AsciiStrCpy (FormatString, Format);\r
2287f237 112\r
113 //\r
9ba6cd30 114 // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments\r
115 // of format in DEBUG string, which is followed by the DEBUG format string.\r
116 // Here we will process the variable arguments and pack them in this area.\r
2287f237 117 //\r
ca9938b8 118 VA_START (VaListMarker, Format);\r
119 for (; *Format != '\0'; Format++) {\r
9ba6cd30 120 //\r
121 // Only format with prefix % is processed.\r
122 //\r
ca9938b8 123 if (*Format != '%') {\r
124 continue;\r
125 }\r
126 Long = FALSE;\r
127 //\r
128 // Parse Flags and Width\r
129 //\r
3d747a89 130 for (Format++; TRUE; Format++) {\r
131 if (*Format == '.' || *Format == '-' || *Format == '+' || *Format == ' ') {\r
9ba6cd30 132 //\r
133 // These characters in format field are omitted.\r
134 //\r
3d747a89 135 continue;\r
136 }\r
137 if (*Format >= '0' && *Format <= '9') {\r
138 //\r
139 // These characters in format field are omitted.\r
140 //\r
141 continue;\r
142 }\r
143 if (*Format == 'L' || *Format == 'l') {\r
9ba6cd30 144 //\r
145 // 'L" or "l" in format field means the number being printed is a UINT64\r
146 //\r
ca9938b8 147 Long = TRUE;\r
3d747a89 148 continue;\r
149 }\r
150 if (*Format == '*') {\r
9ba6cd30 151 //\r
152 // '*' in format field means the precision of the field is specified by\r
153 // a UINTN argument in the argument list.\r
154 //\r
ca9938b8 155 BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);\r
3d747a89 156 continue;\r
157 }\r
158 if (*Format == '\0') {\r
ca9938b8 159 //\r
160 // Make no output if Format string terminates unexpectedly when\r
161 // looking up for flag, width, precision and type. \r
162 //\r
163 Format--;\r
ca9938b8 164 }\r
3d747a89 165 //\r
166 // When valid argument type detected or format string terminates unexpectedly,\r
167 // the inner loop is done.\r
168 //\r
169 break;\r
170 }\r
171 \r
ca9938b8 172 //\r
9ba6cd30 173 // Pack variable arguments into the storage area following EFI_DEBUG_INFO.\r
ca9938b8 174 //\r
3d747a89 175 if ((*Format == 'p') && (sizeof (VOID *) > 4)) {\r
176 Long = TRUE;\r
177 }\r
178 if (*Format == 'p' || *Format == 'X' || *Format == 'x' || *Format == 'd') {\r
ca9938b8 179 if (Long) {\r
180 BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64);\r
181 } else {\r
182 BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int);\r
183 }\r
3d747a89 184 } else if (*Format == 's' || *Format == 'S' || *Format == 'a' || *Format == 'g' || *Format == 't') {\r
ca9938b8 185 BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *);\r
3d747a89 186 } else if (*Format == 'c') {\r
ca9938b8 187 BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);\r
3d747a89 188 } else if (*Format == 'r') {\r
ca9938b8 189 BASE_ARG (BaseListMarker, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);\r
ca9938b8 190 }\r
191\r
192 //\r
193 // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then ASSERT()\r
194 // This indicates that the DEBUG() macro is passing in more argument than can be handled by \r
195 // the EFI_DEBUG_INFO record\r
196 //\r
3d7dfb38 197 ASSERT ((CHAR8 *)BaseListMarker <= FormatString);\r
ca9938b8 198\r
199 //\r
200 // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return\r
201 //\r
3d7dfb38 202 if ((CHAR8 *)BaseListMarker > FormatString) {\r
ca9938b8 203 return;\r
204 }\r
2287f237 205 }\r
ca9938b8 206 VA_END (VaListMarker);\r
2287f237 207\r
ca9938b8 208 //\r
209 // Send the DebugInfo record\r
210 //\r
2287f237 211 REPORT_STATUS_CODE_EX (\r
212 EFI_DEBUG_CODE,\r
213 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED),\r
214 0,\r
215 NULL,\r
216 &gEfiStatusCodeDataTypeDebugGuid,\r
217 DebugInfo,\r
218 TotalSize\r
219 );\r
220}\r
221\r
2287f237 222/**\r
9ba6cd30 223 Prints an assert message containing a filename, line number, and description. \r
2287f237 224 This may be followed by a breakpoint or a dead loop.\r
225\r
226 Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"\r
9ba6cd30 227 to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of \r
228 PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if \r
229 DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then \r
230 CpuDeadLoop() is called. If neither of these bits are set, then this function \r
2287f237 231 returns immediately after the message is printed to the debug output device.\r
584125bc 232 DebugAssert() must actively prevent recursion. If DebugAssert() is called while\r
2287f237 233 processing another DebugAssert(), then DebugAssert() must return immediately.\r
234\r
235 If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.\r
2287f237 236 If Description is NULL, then a <Description> string of "(NULL) Description" is printed.\r
237\r
238 @param FileName Pointer to the name of the source file that generated the assert condition.\r
239 @param LineNumber The line number in the source file that generated the assert condition\r
240 @param Description Pointer to the description of the assert condition.\r
241\r
242**/\r
243VOID\r
244EFIAPI\r
245DebugAssert (\r
246 IN CONST CHAR8 *FileName,\r
247 IN UINTN LineNumber,\r
248 IN CONST CHAR8 *Description\r
249 )\r
250{\r
251 UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof(UINT64)];\r
252 EFI_DEBUG_ASSERT_DATA *AssertData;\r
253 UINTN TotalSize;\r
254 CHAR8 *Temp;\r
9ba6cd30 255 UINTN FileNameSize;\r
256 UINTN DescriptionSize;\r
2287f237 257\r
258 //\r
259 // Make sure it will all fit in the passed in buffer\r
260 //\r
9ba6cd30 261 FileNameSize = AsciiStrSize (FileName);\r
262 DescriptionSize = AsciiStrSize (Description);\r
263 TotalSize = sizeof (EFI_DEBUG_ASSERT_DATA) + FileNameSize + DescriptionSize;\r
1ca88083 264 if (TotalSize <= sizeof (Buffer)) {\r
2287f237 265 //\r
266 // Fill in EFI_DEBUG_ASSERT_DATA\r
267 //\r
268 AssertData = (EFI_DEBUG_ASSERT_DATA *)Buffer;\r
269 AssertData->LineNumber = (UINT32)LineNumber;\r
270\r
271 //\r
272 // Copy Ascii FileName including NULL.\r
273 //\r
274 Temp = AsciiStrCpy ((CHAR8 *)(AssertData + 1), FileName);\r
275\r
276 //\r
277 // Copy Ascii Description\r
278 //\r
9ba6cd30 279 AsciiStrCpy (Temp + FileNameSize, Description);\r
2287f237 280\r
8191cd5e 281 REPORT_STATUS_CODE_EX (\r
2287f237 282 (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),\r
283 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE),\r
8191cd5e
LG
284 0,\r
285 NULL,\r
1872ccab 286 NULL,\r
2287f237 287 AssertData,\r
288 TotalSize\r
289 );\r
290 }\r
291\r
292 //\r
293 // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings\r
294 //\r
9ba6cd30 295 if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {\r
2287f237 296 CpuBreakpoint ();\r
9ba6cd30 297 } else if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {\r
2287f237 298 CpuDeadLoop ();\r
299 }\r
300}\r
301\r
302\r
303/**\r
2287f237 304 Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.\r
305\r
9ba6cd30 306 This function fills Length bytes of Buffer with the value specified by \r
2287f237 307 PcdDebugClearMemoryValue, and returns Buffer.\r
308\r
309 If Buffer is NULL, then ASSERT().\r
9ba6cd30 310 If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). \r
2287f237 311\r
9ba6cd30 312 @param Buffer Pointer to the target buffer to be filled with PcdDebugClearMemoryValue.\r
313 @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue. \r
2287f237 314\r
9ba6cd30 315 @return Buffer Pointer to the target buffer filled with PcdDebugClearMemoryValue.\r
2287f237 316\r
317**/\r
318VOID *\r
319EFIAPI\r
320DebugClearMemory (\r
321 OUT VOID *Buffer,\r
322 IN UINTN Length\r
323 )\r
324{\r
2287f237 325 ASSERT (Buffer != NULL);\r
326\r
9ba6cd30 327 return SetMem (Buffer, Length, PcdGet8 (PcdDebugClearMemoryValue));\r
2287f237 328}\r
329\r
330\r
331/**\r
2287f237 332 Returns TRUE if ASSERT() macros are enabled.\r
333\r
9ba6cd30 334 This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of \r
2287f237 335 PcdDebugProperyMask is set. Otherwise FALSE is returned.\r
336\r
337 @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set.\r
338 @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear.\r
339\r
340**/\r
341BOOLEAN\r
342EFIAPI\r
343DebugAssertEnabled (\r
344 VOID\r
345 )\r
346{\r
9ba6cd30 347 return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);\r
2287f237 348}\r
349\r
350\r
9ba6cd30 351/** \r
352 Returns TRUE if DEBUG() macros are enabled.\r
2287f237 353\r
9ba6cd30 354 This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of \r
2287f237 355 PcdDebugProperyMask is set. Otherwise FALSE is returned.\r
356\r
357 @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.\r
358 @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.\r
359\r
360**/\r
361BOOLEAN\r
362EFIAPI\r
363DebugPrintEnabled (\r
364 VOID\r
365 )\r
366{\r
9ba6cd30 367 return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);\r
2287f237 368}\r
369\r
370\r
9ba6cd30 371/** \r
372 Returns TRUE if DEBUG_CODE() macros are enabled.\r
2287f237 373\r
9ba6cd30 374 This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of \r
2287f237 375 PcdDebugProperyMask is set. Otherwise FALSE is returned.\r
376\r
377 @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set.\r
378 @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear.\r
379\r
380**/\r
381BOOLEAN\r
382EFIAPI\r
383DebugCodeEnabled (\r
384 VOID\r
385 )\r
386{\r
9ba6cd30 387 return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);\r
2287f237 388}\r
389\r
390\r
9ba6cd30 391/** \r
392 Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.\r
2287f237 393\r
9ba6cd30 394 This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of \r
2287f237 395 PcdDebugProperyMask is set. Otherwise FALSE is returned.\r
396\r
9ba6cd30 397 @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set.\r
398 @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear.\r
2287f237 399\r
400**/\r
401BOOLEAN\r
402EFIAPI\r
403DebugClearMemoryEnabled (\r
404 VOID\r
405 )\r
406{\r
9ba6cd30 407 return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);\r
2287f237 408}\r