[EXT2] Upgrade to 0.69
[reactos.git] / boot / freeldr / freeldr / lib / debug.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <freeldr.h>
21 #include <debug.h>
22
23 #if DBG && !defined(_M_ARM)
24
25 // #define DEBUG_ALL
26 // #define DEBUG_WARN
27 // #define DEBUG_ERR
28 // #define DEBUG_INIFILE
29 // #define DEBUG_REACTOS
30 // #define DEBUG_CUSTOM
31 #define DEBUG_NONE
32
33 #define DBG_DEFAULT_LEVELS (ERR_LEVEL|FIXME_LEVEL)
34
35 static UCHAR DbgChannels[DBG_CHANNELS_COUNT];
36
37 #define SCREEN 1
38 #define RS232 2
39 #define BOCHS 4
40
41 #define BOCHS_OUTPUT_PORT 0xE9
42
43 ULONG DebugPort = RS232;
44
45 /* Serial debug connection */
46 ULONG ComPort = 0; // The COM port initializer chooses the first available port starting from COM4 down to COM1.
47 ULONG BaudRate = 115200;
48 ULONG PortIrq = 0; // Not used at the moment.
49
50 BOOLEAN DebugStartOfLine = TRUE;
51
52 VOID DebugInit(BOOLEAN MainInit)
53 {
54 PCHAR CommandLine, PortString, BaudString, IrqString;
55 ULONG Value;
56 CHAR DebugString[256];
57
58 /* Always reset the debugging channels */
59
60 #if defined (DEBUG_ALL)
61 memset(DbgChannels, MAX_LEVEL, DBG_CHANNELS_COUNT);
62 #elif defined (DEBUG_WARN)
63 memset(DbgChannels, WARN_LEVEL|FIXME_LEVEL|ERR_LEVEL, DBG_CHANNELS_COUNT);
64 #elif defined (DEBUG_ERR)
65 memset(DbgChannels, ERR_LEVEL, DBG_CHANNELS_COUNT);
66 #else
67 memset(DbgChannels, 0, DBG_CHANNELS_COUNT);
68 #endif
69
70 #if defined (DEBUG_INIFILE)
71 DbgChannels[DPRINT_INIFILE] = MAX_LEVEL;
72 #elif defined (DEBUG_REACTOS)
73 DbgChannels[DPRINT_REACTOS] = MAX_LEVEL;
74 DbgChannels[DPRINT_REGISTRY] = MAX_LEVEL;
75 #elif defined (DEBUG_CUSTOM)
76 DbgChannels[DPRINT_WARNING] = MAX_LEVEL;
77 DbgChannels[DPRINT_WINDOWS] = MAX_LEVEL;
78 #endif
79
80 /* Check for pre- or main initialization phase */
81 if (!MainInit)
82 {
83 /* Pre-initialization phase: use the FreeLdr command-line debugging string */
84 CommandLine = (PCHAR)CmdLineGetDebugString();
85
86 /* If no command-line is provided, initialize the debug port with default settings */
87 if (CommandLine == NULL)
88 goto Done;
89
90 strcpy(DebugString, CommandLine);
91 }
92 else
93 {
94 /* Main initialization phase: use the FreeLdr INI debugging string */
95
96 ULONG_PTR SectionId;
97
98 if (!IniOpenSection("FreeLoader", &SectionId))
99 return;
100
101 if (!IniReadSettingByName(SectionId, "Debug", DebugString, sizeof(DebugString)))
102 return;
103 }
104
105 /* Get the Command Line */
106 CommandLine = DebugString;
107
108 /* Upcase it */
109 _strupr(CommandLine);
110
111 /* Get the port and baud rate */
112 PortString = strstr(CommandLine, "DEBUGPORT");
113 BaudString = strstr(CommandLine, "BAUDRATE");
114 IrqString = strstr(CommandLine, "IRQ");
115
116 /*
117 * Check if we got /DEBUGPORT parameters.
118 * NOTE: Inspired by reactos/ntoskrnl/kd/kdinit.c, KdInitSystem(...)
119 */
120 while (PortString)
121 {
122 /* Move past the actual string, to reach the port*/
123 PortString += strlen("DEBUGPORT");
124
125 /* Now get past any spaces and skip the equal sign */
126 while (*PortString == ' ') PortString++;
127 PortString++;
128
129 /* Check for possible ports and set the port to use */
130 if (strncmp(PortString, "SCREEN", 6) == 0)
131 {
132 PortString += 6;
133 DebugPort |= SCREEN;
134 }
135 else if (strncmp(PortString, "BOCHS", 5) == 0)
136 {
137 PortString += 5;
138 DebugPort |= BOCHS;
139 }
140 else if (strncmp(PortString, "COM", 3) == 0)
141 {
142 PortString += 3;
143 DebugPort |= RS232;
144
145 /* Set the port to use */
146 Value = atol(PortString);
147 if (Value) ComPort = Value;
148 }
149
150 PortString = strstr(PortString, "DEBUGPORT");
151 }
152
153 /* Check if we got a baud rate */
154 if (BaudString)
155 {
156 /* Move past the actual string, to reach the rate */
157 BaudString += strlen("BAUDRATE");
158
159 /* Now get past any spaces */
160 while (*BaudString == ' ') BaudString++;
161
162 /* And make sure we have a rate */
163 if (*BaudString)
164 {
165 /* Read and set it */
166 Value = atol(BaudString + 1);
167 if (Value) BaudRate = Value;
168 }
169 }
170
171 /* Check Serial Port Settings [IRQ] */
172 if (IrqString)
173 {
174 /* Move past the actual string, to reach the rate */
175 IrqString += strlen("IRQ");
176
177 /* Now get past any spaces */
178 while (*IrqString == ' ') IrqString++;
179
180 /* And make sure we have an IRQ */
181 if (*IrqString)
182 {
183 /* Read and set it */
184 Value = atol(IrqString + 1);
185 if (Value) PortIrq = Value;
186 }
187 }
188
189 Done:
190 /* Try to initialize the port; if it fails, remove the corresponding flag */
191 if (DebugPort & RS232)
192 {
193 if (!Rs232PortInitialize(ComPort, BaudRate))
194 DebugPort &= ~RS232;
195 }
196 }
197
198 VOID DebugPrintChar(UCHAR Character)
199 {
200 if (Character == '\n')
201 DebugStartOfLine = TRUE;
202
203 if (DebugPort & RS232)
204 {
205 if (Character == '\n')
206 Rs232PortPutByte('\r');
207
208 Rs232PortPutByte(Character);
209 }
210 if (DebugPort & BOCHS)
211 {
212 WRITE_PORT_UCHAR((PUCHAR)BOCHS_OUTPUT_PORT, Character);
213 }
214 if (DebugPort & SCREEN)
215 {
216 MachConsPutChar(Character);
217 }
218 }
219
220 ULONG
221 DbgPrint(const char *Format, ...)
222 {
223 va_list ap;
224 int Length;
225 char* ptr;
226 CHAR Buffer[512];
227
228 va_start(ap, Format);
229 Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap);
230 va_end(ap);
231
232 /* Check if we went past the buffer */
233 if (Length == -1)
234 {
235 /* Terminate it if we went over-board */
236 Buffer[sizeof(Buffer) - 1] = '\n';
237
238 /* Put maximum */
239 Length = sizeof(Buffer);
240 }
241
242 ptr = Buffer;
243 while (Length--)
244 DebugPrintChar(*ptr++);
245
246 return 0;
247 }
248
249 VOID
250 DbgPrint2(ULONG Mask, ULONG Level, const char *File, ULONG Line, char *Format, ...)
251 {
252 va_list ap;
253 char Buffer[2096];
254 char *ptr = Buffer;
255
256 /* Mask out unwanted debug messages */
257 if (!(DbgChannels[Mask] & Level) && !(Level & DBG_DEFAULT_LEVELS))
258 {
259 return;
260 }
261
262 /* Print the header if we have started a new line */
263 if (DebugStartOfLine)
264 {
265 DbgPrint("(%s:%lu) ", File, Line);
266
267 switch (Level)
268 {
269 case ERR_LEVEL:
270 DbgPrint("err: ");
271 break;
272 case FIXME_LEVEL:
273 DbgPrint("fixme: ");
274 break;
275 case WARN_LEVEL:
276 DbgPrint("warn: ");
277 break;
278 case TRACE_LEVEL:
279 DbgPrint("trace: ");
280 break;
281 }
282
283 DebugStartOfLine = FALSE;
284 }
285
286 va_start(ap, Format);
287 vsprintf(Buffer, Format, ap);
288 va_end(ap);
289
290 while (*ptr)
291 {
292 DebugPrintChar(*ptr++);
293 }
294 }
295
296 VOID
297 DebugDumpBuffer(ULONG Mask, PVOID Buffer, ULONG Length)
298 {
299 PUCHAR BufPtr = (PUCHAR)Buffer;
300 ULONG Offset, Count, i;
301
302 /* Mask out unwanted debug messages */
303 if (!(DbgChannels[Mask] & TRACE_LEVEL))
304 return;
305
306 DebugStartOfLine = FALSE; // We don't want line headers
307 DbgPrint("Dumping buffer at %p with length of %lu bytes:\n", Buffer, Length);
308
309 Offset = 0;
310 while (Offset < Length)
311 {
312 /* We don't want line headers */
313 DebugStartOfLine = FALSE;
314
315 /* Print the offset */
316 DbgPrint("%04x:\t", Offset);
317
318 /* Print either 16 or the remaining number of bytes */
319 Count = min(Length - Offset, 16);
320 for (i = 0; i < Count; i++, Offset++)
321 {
322 DbgPrint("%02x%c", BufPtr[Offset], (i == 7) ? '-' : ' ');
323 }
324
325 DbgPrint("\n");
326 }
327 }
328
329 static BOOLEAN
330 DbgAddDebugChannel(CHAR* channel, CHAR* level, CHAR op)
331 {
332 int iLevel, iChannel;
333
334 if (channel == NULL || *channel == '\0' || strlen(channel) == 0)
335 return FALSE;
336
337 if (level == NULL || *level == '\0' || strlen(level) == 0)
338 iLevel = MAX_LEVEL;
339 else if (strcmp(level, "err") == 0)
340 iLevel = ERR_LEVEL;
341 else if (strcmp(level, "fixme") == 0)
342 iLevel = FIXME_LEVEL;
343 else if (strcmp(level, "warn") == 0)
344 iLevel = WARN_LEVEL;
345 else if (strcmp(level, "trace") == 0)
346 iLevel = TRACE_LEVEL;
347 else
348 return FALSE;
349
350 if (strcmp(channel, "memory" ) == 0) iChannel = DPRINT_MEMORY;
351 else if (strcmp(channel, "filesystem") == 0) iChannel = DPRINT_FILESYSTEM;
352 else if (strcmp(channel, "inifile" ) == 0) iChannel = DPRINT_INIFILE;
353 else if (strcmp(channel, "ui" ) == 0) iChannel = DPRINT_UI;
354 else if (strcmp(channel, "disk" ) == 0) iChannel = DPRINT_DISK;
355 else if (strcmp(channel, "cache" ) == 0) iChannel = DPRINT_CACHE;
356 else if (strcmp(channel, "registry" ) == 0) iChannel = DPRINT_REGISTRY;
357 else if (strcmp(channel, "linux" ) == 0) iChannel = DPRINT_LINUX;
358 else if (strcmp(channel, "hwdetect" ) == 0) iChannel = DPRINT_HWDETECT;
359 else if (strcmp(channel, "windows" ) == 0) iChannel = DPRINT_WINDOWS;
360 else if (strcmp(channel, "peloader" ) == 0) iChannel = DPRINT_PELOADER;
361 else if (strcmp(channel, "scsiport" ) == 0) iChannel = DPRINT_SCSIPORT;
362 else if (strcmp(channel, "heap" ) == 0) iChannel = DPRINT_HEAP;
363 else if (strcmp(channel, "all" ) == 0)
364 {
365 int i;
366
367 for (i = 0; i < DBG_CHANNELS_COUNT; i++)
368 {
369 if (op == '+')
370 DbgChannels[i] |= iLevel;
371 else
372 DbgChannels[i] &= ~iLevel;
373 }
374
375 return TRUE;
376 }
377 else return FALSE;
378
379 if (op == '+')
380 DbgChannels[iChannel] |= iLevel;
381 else
382 DbgChannels[iChannel] &= ~iLevel;
383
384 return TRUE;
385 }
386
387 VOID
388 DbgParseDebugChannels(PCHAR Value)
389 {
390 CHAR *str, *separator, *c, op;
391
392 str = Value;
393
394 do
395 {
396 separator = strchr(str, ',');
397 if (separator != NULL)
398 *separator = '\0';
399
400 c = strchr(str, '+');
401 if (c == NULL)
402 c = strchr(str, '-');
403
404 if (c != NULL)
405 {
406 op = *c;
407 *c = '\0';
408 c++;
409
410 DbgAddDebugChannel(c, str, op);
411 }
412
413 str = separator + 1;
414 } while (separator != NULL);
415 }
416
417 #else
418
419 ULONG
420 DbgPrint(PCCH Format, ...)
421 {
422 return 0;
423 }
424
425 #endif // DBG
426
427 ULONG
428 MsgBoxPrint(const char *Format, ...)
429 {
430 va_list ap;
431 CHAR Buffer[512];
432 ULONG Length;
433
434 va_start(ap, Format);
435
436 /* Construct a string */
437 Length = _vsnprintf(Buffer, 512, Format, ap);
438
439 /* Check if we went past the buffer */
440 if (Length == MAXULONG)
441 {
442 /* Terminate it if we went over-board */
443 Buffer[sizeof(Buffer) - 1] = '\n';
444
445 /* Put maximum */
446 Length = sizeof(Buffer);
447 }
448
449 /* Show it as a message box */
450 UiMessageBox(Buffer);
451
452 /* Cleanup and exit */
453 va_end(ap);
454 return 0;
455 }
456
457 // DECLSPEC_NORETURN
458 VOID
459 NTAPI
460 KeBugCheckEx(
461 IN ULONG BugCheckCode,
462 IN ULONG_PTR BugCheckParameter1,
463 IN ULONG_PTR BugCheckParameter2,
464 IN ULONG_PTR BugCheckParameter3,
465 IN ULONG_PTR BugCheckParameter4)
466 {
467 char Buffer[70];
468 sprintf(Buffer, "*** STOP: 0x%08lX (0x%08lX, 0x%08lX, 0x%08lX, 0x%08lX)",
469 BugCheckCode, BugCheckParameter1, BugCheckParameter2,
470 BugCheckParameter3, BugCheckParameter4);
471 UiMessageBoxCritical(Buffer);
472 ASSERT(FALSE);
473 for (;;);
474 }
475
476 VOID
477 NTAPI
478 RtlAssert(IN PVOID FailedAssertion,
479 IN PVOID FileName,
480 IN ULONG LineNumber,
481 IN PCHAR Message OPTIONAL)
482 {
483 if (Message)
484 {
485 DbgPrint("Assertion \'%s\' failed at %s line %u: %s\n",
486 (PCHAR)FailedAssertion,
487 (PCHAR)FileName,
488 LineNumber,
489 Message);
490 }
491 else
492 {
493 DbgPrint("Assertion \'%s\' failed at %s line %u\n",
494 (PCHAR)FailedAssertion,
495 (PCHAR)FileName,
496 LineNumber);
497 }
498
499 DbgBreakPoint();
500 }
501
502 char *BugCodeStrings[] =
503 {
504 "TEST_BUGCHECK",
505 "MISSING_HARDWARE_REQUIREMENTS",
506 "FREELDR_IMAGE_CORRUPTION",
507 "MEMORY_INIT_FAILURE",
508 };
509
510 ULONG_PTR BugCheckInfo[5];