Create the AHCI branch for Aman's work
[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 Idx, Idx2;
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 for (Idx = 0; Idx < Length; )
310 {
311 DebugStartOfLine = FALSE; // We don't want line headers
312
313 if (Idx < 0x0010)
314 DbgPrint("000%x:\t", Idx);
315 else if (Idx < 0x0100)
316 DbgPrint("00%x:\t", Idx);
317 else if (Idx < 0x1000)
318 DbgPrint("0%x:\t", Idx);
319 else
320 DbgPrint("%x:\t", Idx);
321
322 for (Idx2 = 0; Idx2 < 16; Idx2++, Idx++)
323 {
324 if (BufPtr[Idx] < 0x10)
325 {
326 DbgPrint("0");
327 }
328 DbgPrint("%x", BufPtr[Idx]);
329
330 if (Idx2 == 7)
331 {
332 DbgPrint("-");
333 }
334 else
335 {
336 DbgPrint(" ");
337 }
338 }
339
340 Idx -= 16;
341 DbgPrint(" ");
342
343 for (Idx2 = 0; Idx2 < 16; Idx2++, Idx++)
344 {
345 if ((BufPtr[Idx] > 20) && (BufPtr[Idx] < 0x80))
346 {
347 DbgPrint("%c", BufPtr[Idx]);
348 }
349 else
350 {
351 DbgPrint(".");
352 }
353 }
354
355 DbgPrint("\n");
356 }
357 }
358
359 static BOOLEAN
360 DbgAddDebugChannel(CHAR* channel, CHAR* level, CHAR op)
361 {
362 int iLevel, iChannel;
363
364 if (channel == NULL || *channel == '\0' || strlen(channel) == 0)
365 return FALSE;
366
367 if (level == NULL || *level == '\0' || strlen(level) == 0)
368 iLevel = MAX_LEVEL;
369 else if (strcmp(level, "err") == 0)
370 iLevel = ERR_LEVEL;
371 else if (strcmp(level, "fixme") == 0)
372 iLevel = FIXME_LEVEL;
373 else if (strcmp(level, "warn") == 0)
374 iLevel = WARN_LEVEL;
375 else if (strcmp(level, "trace") == 0)
376 iLevel = TRACE_LEVEL;
377 else
378 return FALSE;
379
380 if (strcmp(channel, "memory" ) == 0) iChannel = DPRINT_MEMORY;
381 else if (strcmp(channel, "filesystem") == 0) iChannel = DPRINT_FILESYSTEM;
382 else if (strcmp(channel, "inifile" ) == 0) iChannel = DPRINT_INIFILE;
383 else if (strcmp(channel, "ui" ) == 0) iChannel = DPRINT_UI;
384 else if (strcmp(channel, "disk" ) == 0) iChannel = DPRINT_DISK;
385 else if (strcmp(channel, "cache" ) == 0) iChannel = DPRINT_CACHE;
386 else if (strcmp(channel, "registry" ) == 0) iChannel = DPRINT_REGISTRY;
387 else if (strcmp(channel, "linux" ) == 0) iChannel = DPRINT_LINUX;
388 else if (strcmp(channel, "hwdetect" ) == 0) iChannel = DPRINT_HWDETECT;
389 else if (strcmp(channel, "windows" ) == 0) iChannel = DPRINT_WINDOWS;
390 else if (strcmp(channel, "peloader" ) == 0) iChannel = DPRINT_PELOADER;
391 else if (strcmp(channel, "scsiport" ) == 0) iChannel = DPRINT_SCSIPORT;
392 else if (strcmp(channel, "heap" ) == 0) iChannel = DPRINT_HEAP;
393 else if (strcmp(channel, "all" ) == 0)
394 {
395 int i;
396
397 for (i = 0; i < DBG_CHANNELS_COUNT; i++)
398 {
399 if (op == '+')
400 DbgChannels[i] |= iLevel;
401 else
402 DbgChannels[i] &= ~iLevel;
403 }
404
405 return TRUE;
406 }
407 else return FALSE;
408
409 if (op == '+')
410 DbgChannels[iChannel] |= iLevel;
411 else
412 DbgChannels[iChannel] &= ~iLevel;
413
414 return TRUE;
415 }
416
417 VOID
418 DbgParseDebugChannels(PCHAR Value)
419 {
420 CHAR *str, *separator, *c, op;
421
422 str = Value;
423
424 do
425 {
426 separator = strchr(str, ',');
427 if (separator != NULL)
428 *separator = '\0';
429
430 c = strchr(str, '+');
431 if (c == NULL)
432 c = strchr(str, '-');
433
434 if (c != NULL)
435 {
436 op = *c;
437 *c = '\0';
438 c++;
439
440 DbgAddDebugChannel(c, str, op);
441 }
442
443 str = separator + 1;
444 } while (separator != NULL);
445 }
446
447 #else
448
449 ULONG
450 DbgPrint(PCCH Format, ...)
451 {
452 return 0;
453 }
454
455 #endif // DBG
456
457 ULONG
458 MsgBoxPrint(const char *Format, ...)
459 {
460 va_list ap;
461 CHAR Buffer[512];
462 ULONG Length;
463
464 va_start(ap, Format);
465
466 /* Construct a string */
467 Length = _vsnprintf(Buffer, 512, Format, ap);
468
469 /* Check if we went past the buffer */
470 if (Length == MAXULONG)
471 {
472 /* Terminate it if we went over-board */
473 Buffer[sizeof(Buffer) - 1] = '\n';
474
475 /* Put maximum */
476 Length = sizeof(Buffer);
477 }
478
479 /* Show it as a message box */
480 UiMessageBox(Buffer);
481
482 /* Cleanup and exit */
483 va_end(ap);
484 return 0;
485 }
486
487 // DECLSPEC_NORETURN
488 VOID
489 NTAPI
490 KeBugCheckEx(
491 IN ULONG BugCheckCode,
492 IN ULONG_PTR BugCheckParameter1,
493 IN ULONG_PTR BugCheckParameter2,
494 IN ULONG_PTR BugCheckParameter3,
495 IN ULONG_PTR BugCheckParameter4)
496 {
497 char Buffer[70];
498 sprintf(Buffer, "*** STOP: 0x%08lX (0x%08lX, 0x%08lX, 0x%08lX, 0x%08lX)",
499 BugCheckCode, BugCheckParameter1, BugCheckParameter2,
500 BugCheckParameter3, BugCheckParameter4);
501 UiMessageBoxCritical(Buffer);
502 ASSERT(FALSE);
503 for (;;);
504 }
505
506 VOID
507 NTAPI
508 RtlAssert(IN PVOID FailedAssertion,
509 IN PVOID FileName,
510 IN ULONG LineNumber,
511 IN PCHAR Message OPTIONAL)
512 {
513 if (Message)
514 {
515 DbgPrint("Assertion \'%s\' failed at %s line %u: %s\n",
516 (PCHAR)FailedAssertion,
517 (PCHAR)FileName,
518 LineNumber,
519 Message);
520 }
521 else
522 {
523 DbgPrint("Assertion \'%s\' failed at %s line %u\n",
524 (PCHAR)FailedAssertion,
525 (PCHAR)FileName,
526 LineNumber);
527 }
528
529 DbgBreakPoint();
530 }
531
532 char *BugCodeStrings[] =
533 {
534 "TEST_BUGCHECK",
535 "MISSING_HARDWARE_REQUIREMENTS",
536 "FREELDR_IMAGE_CORRUPTION",
537 "MEMORY_INIT_FAILURE",
538 };
539
540 ULONG_PTR BugCheckInfo[5];