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