xref: /reactos/boot/freeldr/freeldr/lib/debug.c (revision 7bee32d2)
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
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 #if defined(SARCH_PC98)
47 ULONG BaudRate = 9600;
48 #else
49 ULONG BaudRate = 115200;
50 #endif
51 
52 ULONG ComPort  = 0; // The COM port initializer chooses the first available port starting from COM4 down to COM1.
53 ULONG PortIrq  = 0; // Not used at the moment.
54 
55 BOOLEAN DebugStartOfLine = TRUE;
56 
57 #ifdef UEFIBOOT
58 VOID
59 ARMWriteToUART(UCHAR Data);
60 #endif
61 
62 VOID
DebugInit(_In_ PCSTR DebugString)63 DebugInit(
64     _In_ PCSTR DebugString)
65 {
66     static BOOLEAN Initialized = FALSE;
67     PSTR CommandLine, PortString, BaudString, IrqString;
68     ULONG Value;
69     CHAR DbgStringBuffer[256];
70 
71     /* Always reset the debugging channels */
72 
73 #if defined (DEBUG_ALL)
74     memset(DbgChannels, MAX_LEVEL, DBG_CHANNELS_COUNT);
75 #elif defined (DEBUG_WARN)
76     memset(DbgChannels, WARN_LEVEL|FIXME_LEVEL|ERR_LEVEL, DBG_CHANNELS_COUNT);
77 #elif defined (DEBUG_ERR)
78     memset(DbgChannels, ERR_LEVEL, DBG_CHANNELS_COUNT);
79 #else
80     memset(DbgChannels, 0, DBG_CHANNELS_COUNT);
81 #endif
82 
83 #if defined (DEBUG_INIFILE)
84     DbgChannels[DPRINT_INIFILE] = MAX_LEVEL;
85 #elif defined (DEBUG_REACTOS)
86     DbgChannels[DPRINT_REACTOS] = MAX_LEVEL;
87     DbgChannels[DPRINT_REGISTRY] = MAX_LEVEL;
88 #elif defined (DEBUG_CUSTOM)
89     DbgChannels[DPRINT_WARNING] = MAX_LEVEL;
90     DbgChannels[DPRINT_WINDOWS] = MAX_LEVEL;
91 #endif
92 
93     CommandLine = NULL;
94     if (!DebugString || !*DebugString)
95     {
96         /* No command-line is provided: during pre-initialization,
97          * initialize the debug port with default settings;
98          * otherwise just return during main initialization */
99         if (!Initialized)
100             goto Done;
101         return;
102     }
103 
104     /* Get a copy of the command-line */
105     strcpy(DbgStringBuffer, DebugString);
106     CommandLine = DbgStringBuffer;
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     Initialized = TRUE;
191 
192     /* Try to initialize the port; if it fails, remove the corresponding flag */
193     if (DebugPort & RS232)
194     {
195         if (!Rs232PortInitialize(ComPort, BaudRate))
196             DebugPort &= ~RS232;
197     }
198 }
199 
DebugPrintChar(UCHAR Character)200 VOID DebugPrintChar(UCHAR Character)
201 {
202     if (Character == '\n')
203         DebugStartOfLine = TRUE;
204 
205     if (DebugPort & RS232)
206     {
207         if (Character == '\n')
208             Rs232PortPutByte('\r');
209 
210         Rs232PortPutByte(Character);
211     }
212     if (DebugPort & BOCHS)
213     {
214         WRITE_PORT_UCHAR((PUCHAR)BOCHS_OUTPUT_PORT, Character);
215     }
216     if (DebugPort & SCREEN)
217     {
218         MachConsPutChar(Character);
219     }
220 }
221 
222 ULONG
DbgPrint(const char * Format,...)223 DbgPrint(const char *Format, ...)
224 {
225     va_list ap;
226     int Length;
227     char* ptr;
228     CHAR Buffer[512];
229 
230     va_start(ap, Format);
231     Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap);
232     va_end(ap);
233 
234     /* Check if we went past the buffer */
235     if (Length == -1)
236     {
237         /* Terminate it if we went over-board */
238         Buffer[sizeof(Buffer) - 1] = '\n';
239 
240         /* Put maximum */
241         Length = sizeof(Buffer);
242     }
243 
244     ptr = Buffer;
245     while (Length--)
246         DebugPrintChar(*ptr++);
247 
248     return 0;
249 }
250 
251 VOID
DbgPrint2(ULONG Mask,ULONG Level,const char * File,ULONG Line,char * Format,...)252 DbgPrint2(ULONG Mask, ULONG Level, const char *File, ULONG Line, char *Format, ...)
253 {
254     va_list ap;
255     char Buffer[2096];
256     char *ptr = Buffer;
257 
258     /* Mask out unwanted debug messages */
259     if (!(DbgChannels[Mask] & Level) && !(Level & DBG_DEFAULT_LEVELS))
260     {
261         return;
262     }
263 
264     /* Print the header if we have started a new line */
265     if (DebugStartOfLine)
266     {
267         DbgPrint("(%s:%lu) ", File, Line);
268 
269         switch (Level)
270         {
271             case ERR_LEVEL:
272                 DbgPrint("err: ");
273                 break;
274             case FIXME_LEVEL:
275                 DbgPrint("fixme: ");
276                 break;
277             case WARN_LEVEL:
278                 DbgPrint("warn: ");
279                 break;
280             case TRACE_LEVEL:
281                 DbgPrint("trace: ");
282                 break;
283         }
284 
285         DebugStartOfLine = FALSE;
286     }
287 
288     va_start(ap, Format);
289     vsprintf(Buffer, Format, ap);
290     va_end(ap);
291 
292     while (*ptr)
293     {
294         DebugPrintChar(*ptr++);
295     }
296 }
297 
298 VOID
DebugDumpBuffer(ULONG Mask,PVOID Buffer,ULONG Length)299 DebugDumpBuffer(ULONG Mask, PVOID Buffer, ULONG Length)
300 {
301     PUCHAR BufPtr = (PUCHAR)Buffer;
302     ULONG Offset, Count, i;
303 
304     /* Mask out unwanted debug messages */
305     if (!(DbgChannels[Mask] & TRACE_LEVEL))
306         return;
307 
308     DebugStartOfLine = FALSE; // We don't want line headers
309     DbgPrint("Dumping buffer at %p with length of %lu bytes:\n", Buffer, Length);
310 
311     Offset = 0;
312     while (Offset < Length)
313     {
314         /* We don't want line headers */
315         DebugStartOfLine = FALSE;
316 
317         /* Print the offset */
318         DbgPrint("%04x:\t", Offset);
319 
320         /* Print either 16 or the remaining number of bytes */
321         Count = min(Length - Offset, 16);
322         for (i = 0; i < Count; i++, Offset++)
323         {
324             DbgPrint("%02x%c", BufPtr[Offset], (i == 7) ? '-' : ' ');
325         }
326 
327         DbgPrint("\n");
328     }
329 }
330 
331 VOID
DebugDisableScreenPort(VOID)332 DebugDisableScreenPort(VOID)
333 {
334     DebugPort &= ~SCREEN;
335 }
336 
337 static BOOLEAN
DbgAddDebugChannel(CHAR * channel,CHAR * level,CHAR op)338 DbgAddDebugChannel(CHAR* channel, CHAR* level, CHAR op)
339 {
340     int iLevel, iChannel;
341 
342     if (channel == NULL || *channel == '\0' || strlen(channel) == 0)
343         return FALSE;
344 
345     if (level == NULL || *level == '\0' || strlen(level) == 0)
346         iLevel = MAX_LEVEL;
347     else if (strcmp(level, "err") == 0)
348         iLevel = ERR_LEVEL;
349     else if (strcmp(level, "fixme") == 0)
350         iLevel = FIXME_LEVEL;
351     else if (strcmp(level, "warn") == 0)
352         iLevel = WARN_LEVEL;
353     else if (strcmp(level, "trace") == 0)
354         iLevel = TRACE_LEVEL;
355     else
356         return FALSE;
357 
358          if (strcmp(channel, "memory"    ) == 0) iChannel = DPRINT_MEMORY;
359     else if (strcmp(channel, "filesystem") == 0) iChannel = DPRINT_FILESYSTEM;
360     else if (strcmp(channel, "inifile"   ) == 0) iChannel = DPRINT_INIFILE;
361     else if (strcmp(channel, "ui"        ) == 0) iChannel = DPRINT_UI;
362     else if (strcmp(channel, "disk"      ) == 0) iChannel = DPRINT_DISK;
363     else if (strcmp(channel, "cache"     ) == 0) iChannel = DPRINT_CACHE;
364     else if (strcmp(channel, "registry"  ) == 0) iChannel = DPRINT_REGISTRY;
365     else if (strcmp(channel, "linux"     ) == 0) iChannel = DPRINT_LINUX;
366     else if (strcmp(channel, "hwdetect"  ) == 0) iChannel = DPRINT_HWDETECT;
367     else if (strcmp(channel, "windows"   ) == 0) iChannel = DPRINT_WINDOWS;
368     else if (strcmp(channel, "peloader"  ) == 0) iChannel = DPRINT_PELOADER;
369     else if (strcmp(channel, "scsiport"  ) == 0) iChannel = DPRINT_SCSIPORT;
370     else if (strcmp(channel, "heap"      ) == 0) iChannel = DPRINT_HEAP;
371     else if (strcmp(channel, "all"       ) == 0)
372     {
373         int i;
374 
375         for (i = 0; i < DBG_CHANNELS_COUNT; i++)
376         {
377             if (op == '+')
378                 DbgChannels[i] |= iLevel;
379             else
380                 DbgChannels[i] &= ~iLevel;
381         }
382 
383         return TRUE;
384     }
385     else return FALSE;
386 
387     if (op == '+')
388         DbgChannels[iChannel] |= iLevel;
389     else
390         DbgChannels[iChannel] &= ~iLevel;
391 
392     return TRUE;
393 }
394 
395 VOID
DbgParseDebugChannels(PCHAR Value)396 DbgParseDebugChannels(PCHAR Value)
397 {
398     CHAR *str, *separator, *c, op;
399 
400     str = Value;
401 
402     do
403     {
404         separator = strchr(str, ',');
405         if (separator != NULL)
406             *separator = '\0';
407 
408         c = strchr(str, '+');
409         if (c == NULL)
410             c = strchr(str, '-');
411 
412         if (c != NULL)
413         {
414             op = *c;
415             *c = '\0';
416             c++;
417 
418             DbgAddDebugChannel(c, str, op);
419         }
420 
421         str = separator + 1;
422     } while (separator != NULL);
423 }
424 
425 #else
426 
427 ULONG
DbgPrint(PCCH Format,...)428 DbgPrint(PCCH Format, ...)
429 {
430     return 0;
431 }
432 
433 #endif // DBG
434 
435 ULONG
MsgBoxPrint(const char * Format,...)436 MsgBoxPrint(const char *Format, ...)
437 {
438     va_list ap;
439     CHAR Buffer[512];
440     ULONG Length;
441 
442     va_start(ap, Format);
443 
444     /* Construct a string */
445     Length = _vsnprintf(Buffer, 512, Format, ap);
446 
447     /* Check if we went past the buffer */
448     if (Length == MAXULONG)
449     {
450         /* Terminate it if we went over-board */
451         Buffer[sizeof(Buffer) - 1] = '\n';
452 
453         /* Put maximum */
454         Length = sizeof(Buffer);
455     }
456 
457     /* Show it as a message box */
458     UiMessageBox(Buffer);
459 
460     /* Cleanup and exit */
461     va_end(ap);
462     return 0;
463 }
464 
465 DECLSPEC_NORETURN
466 VOID
467 NTAPI
KeBugCheckEx(IN ULONG BugCheckCode,IN ULONG_PTR BugCheckParameter1,IN ULONG_PTR BugCheckParameter2,IN ULONG_PTR BugCheckParameter3,IN ULONG_PTR BugCheckParameter4)468 KeBugCheckEx(
469     IN ULONG  BugCheckCode,
470     IN ULONG_PTR  BugCheckParameter1,
471     IN ULONG_PTR  BugCheckParameter2,
472     IN ULONG_PTR  BugCheckParameter3,
473     IN ULONG_PTR  BugCheckParameter4)
474 {
475     char Buffer[70];
476 
477     sprintf(Buffer,
478             "*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)",
479             BugCheckCode,
480             (PVOID)BugCheckParameter1,
481             (PVOID)BugCheckParameter2,
482             (PVOID)BugCheckParameter3,
483             (PVOID)BugCheckParameter4);
484 
485     UiMessageBoxCritical(Buffer);
486     ASSERT(FALSE);
487     for (;;);
488 }
489 
490 VOID
491 NTAPI
RtlAssert(IN PVOID FailedAssertion,IN PVOID FileName,IN ULONG LineNumber,IN PCHAR Message OPTIONAL)492 RtlAssert(IN PVOID FailedAssertion,
493           IN PVOID FileName,
494           IN ULONG LineNumber,
495           IN PCHAR Message OPTIONAL)
496 {
497     if (Message)
498     {
499         DbgPrint("Assertion \'%s\' failed at %s line %lu: %s\n",
500                  (PCHAR)FailedAssertion,
501                  (PCHAR)FileName,
502                  LineNumber,
503                  Message);
504     }
505     else
506     {
507         DbgPrint("Assertion \'%s\' failed at %s line %lu\n",
508                  (PCHAR)FailedAssertion,
509                  (PCHAR)FileName,
510                  LineNumber);
511     }
512 
513     DbgBreakPoint();
514 }
515 
516 char *BugCodeStrings[] =
517 {
518     "TEST_BUGCHECK",
519     "MISSING_HARDWARE_REQUIREMENTS",
520     "FREELDR_IMAGE_CORRUPTION",
521     "MEMORY_INIT_FAILURE",
522 #ifdef UEFIBOOT
523     "EXIT_BOOTSERVICES_FAILURE",
524 #endif
525 };
526 
527 ULONG_PTR BugCheckInfo[5];
528