[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / 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
22 #include <debug.h>
23
24 #if DBG && !defined(_M_ARM)
25
26 // #define DEBUG_ALL
27 // #define DEBUG_WARN
28 // #define DEBUG_ERR
29 // #define DEBUG_INIFILE
30 // #define DEBUG_REACTOS
31 // #define DEBUG_CUSTOM
32 #define DEBUG_NONE
33
34 #define DBG_DEFAULT_LEVELS (ERR_LEVEL|FIXME_LEVEL)
35
36 #define SCREEN 1
37 #define RS232 2
38 #define BOCHS 4
39
40 #define COM1 1
41 #define COM2 2
42 #define COM3 3
43 #define COM4 4
44
45 #define BOCHS_OUTPUT_PORT 0xe9
46
47 static UCHAR DbgChannels[DBG_CHANNELS_COUNT];
48
49 ULONG DebugPort = RS232;
50 // ULONG DebugPort = SCREEN;
51 // ULONG DebugPort = BOCHS;
52 // ULONG DebugPort = SCREEN|BOCHS;
53 #ifdef _WINKD_
54 /* COM1 is the WinDbg port */
55 ULONG ComPort = COM2;
56 #else
57 ULONG ComPort = COM1;
58 #endif
59 // ULONG BaudRate = 19200;
60 ULONG BaudRate = 115200;
61
62 BOOLEAN DebugStartOfLine = TRUE;
63
64 VOID DebugInit(VOID)
65 {
66 #if defined (DEBUG_ALL)
67 memset(DbgChannels, MAX_LEVEL, DBG_CHANNELS_COUNT);
68 #elif defined (DEBUG_WARN)
69 memset(DbgChannels, WARN_LEVEL|FIXME_LEVEL|ERR_LEVEL, DBG_CHANNELS_COUNT);
70 #elif defined (DEBUG_ERR)
71 memset(DbgChannels, ERR_LEVEL, DBG_CHANNELS_COUNT);
72 #else
73 memset(DbgChannels, 0, DBG_CHANNELS_COUNT);
74 #endif
75
76 #if defined (DEBUG_INIFILE)
77 DbgChannels[DPRINT_INIFILE] = MAX_LEVEL;
78 #elif defined (DEBUG_REACTOS)
79 DbgChannels[DPRINT_REACTOS] = MAX_LEVEL;
80 DbgChannels[DPRINT_REGISTRY] = MAX_LEVEL;
81 #elif defined (DEBUG_CUSTOM)
82 DbgChannels[DPRINT_WARNING] = MAX_LEVEL;
83 DbgChannels[DPRINT_WINDOWS] = MAX_LEVEL;
84 #endif
85
86 if (DebugPort & RS232)
87 {
88 Rs232PortInitialize(ComPort, BaudRate);
89 }
90 }
91
92 VOID DebugPrintChar(UCHAR Character)
93 {
94 if (Character == '\n')
95 DebugStartOfLine = TRUE;
96
97 if (DebugPort & RS232)
98 {
99 if (Character == '\n')
100 Rs232PortPutByte('\r');
101
102 Rs232PortPutByte(Character);
103 }
104 if (DebugPort & BOCHS)
105 {
106 WRITE_PORT_UCHAR((PUCHAR)BOCHS_OUTPUT_PORT, Character);
107 }
108 if (DebugPort & SCREEN)
109 {
110 MachConsPutChar(Character);
111 }
112 }
113
114 ULONG
115 DbgPrint(const char *Format, ...)
116 {
117 int i;
118 int Length;
119 va_list ap;
120 CHAR Buffer[512];
121
122 va_start(ap, Format);
123 Length = _vsnprintf(Buffer, sizeof(Buffer), Format, ap);
124 va_end(ap);
125
126 /* Check if we went past the buffer */
127 if (Length == -1)
128 {
129 /* Terminate it if we went over-board */
130 Buffer[sizeof(Buffer) - 1] = '\n';
131
132 /* Put maximum */
133 Length = sizeof(Buffer);
134 }
135
136 for (i = 0; i < Length; i++)
137 {
138 DebugPrintChar(Buffer[i]);
139 }
140
141 return 0;
142 }
143
144 VOID
145 DbgPrint2(ULONG Mask, ULONG Level, const char *File, ULONG Line, char *Format, ...)
146 {
147 va_list ap;
148 char Buffer[2096];
149 char *ptr = Buffer;
150
151 /* Mask out unwanted debug messages */
152 if (!(DbgChannels[Mask] & Level) && !(Level & DBG_DEFAULT_LEVELS ))
153 {
154 return;
155 }
156
157 /* Print the header if we have started a new line */
158 if (DebugStartOfLine)
159 {
160 DbgPrint("(%s:%lu) ", File, Line);
161
162 switch (Level)
163 {
164 case ERR_LEVEL:
165 DbgPrint("err: ");
166 break;
167 case FIXME_LEVEL:
168 DbgPrint("fixme: ");
169 break;
170 case WARN_LEVEL:
171 DbgPrint("warn: ");
172 break;
173 case TRACE_LEVEL:
174 DbgPrint("trace: ");
175 break;
176 }
177
178 DebugStartOfLine = FALSE;
179 }
180
181 va_start(ap, Format);
182 vsprintf(Buffer, Format, ap);
183 va_end(ap);
184
185 while (*ptr)
186 {
187 DebugPrintChar(*ptr++);
188 }
189 }
190
191 VOID
192 DebugDumpBuffer(ULONG Mask, PVOID Buffer, ULONG Length)
193 {
194 PUCHAR BufPtr = (PUCHAR)Buffer;
195 ULONG Idx;
196 ULONG Idx2;
197
198 /* Mask out unwanted debug messages */
199 if (!(DbgChannels[Mask] & TRACE_LEVEL))
200 return;
201
202 DebugStartOfLine = FALSE; // We don't want line headers
203 DbgPrint("Dumping buffer at %p with length of %lu bytes:\n", Buffer, Length);
204
205 for (Idx=0; Idx<Length; )
206 {
207 DebugStartOfLine = FALSE; // We don't want line headers
208
209 if (Idx < 0x0010)
210 DbgPrint("000%x:\t", Idx);
211 else if (Idx < 0x0100)
212 DbgPrint("00%x:\t", Idx);
213 else if (Idx < 0x1000)
214 DbgPrint("0%x:\t", Idx);
215 else
216 DbgPrint("%x:\t", Idx);
217
218 for (Idx2=0; Idx2<16; Idx2++,Idx++)
219 {
220 if (BufPtr[Idx] < 0x10)
221 {
222 DbgPrint("0");
223 }
224 DbgPrint("%x", BufPtr[Idx]);
225
226 if (Idx2 == 7)
227 {
228 DbgPrint("-");
229 }
230 else
231 {
232 DbgPrint(" ");
233 }
234 }
235
236 Idx -= 16;
237 DbgPrint(" ");
238
239 for (Idx2=0; Idx2<16; Idx2++,Idx++)
240 {
241 if ((BufPtr[Idx] > 20) && (BufPtr[Idx] < 0x80))
242 {
243 DbgPrint("%c", BufPtr[Idx]);
244 }
245 else
246 {
247 DbgPrint(".");
248 }
249 }
250
251 DbgPrint("\n");
252 }
253 }
254
255 static BOOLEAN
256 DbgAddDebugChannel(CHAR* channel, CHAR* level, CHAR op)
257 {
258 int iLevel, iChannel;
259
260 if (channel == NULL || *channel == L'\0' || strlen(channel) == 0 )
261 return FALSE;
262
263 if (level == NULL || *level == L'\0' || strlen(level) == 0 )
264 iLevel = MAX_LEVEL;
265 else if (strcmp(level, "err") == 0)
266 iLevel = ERR_LEVEL;
267 else if (strcmp(level, "fixme") == 0)
268 iLevel = FIXME_LEVEL;
269 else if (strcmp(level, "warn") == 0)
270 iLevel = WARN_LEVEL;
271 else if (strcmp(level, "trace") == 0)
272 iLevel = TRACE_LEVEL;
273 else
274 return FALSE;
275
276 if (strcmp(channel, "memory" ) == 0) iChannel = DPRINT_MEMORY;
277 else if (strcmp(channel, "filesystem") == 0) iChannel = DPRINT_FILESYSTEM;
278 else if (strcmp(channel, "inifile" ) == 0) iChannel = DPRINT_INIFILE;
279 else if (strcmp(channel, "ui" ) == 0) iChannel = DPRINT_UI;
280 else if (strcmp(channel, "disk" ) == 0) iChannel = DPRINT_DISK;
281 else if (strcmp(channel, "cache" ) == 0) iChannel = DPRINT_CACHE;
282 else if (strcmp(channel, "registry" ) == 0) iChannel = DPRINT_REGISTRY;
283 else if (strcmp(channel, "linux" ) == 0) iChannel = DPRINT_LINUX;
284 else if (strcmp(channel, "hwdetect" ) == 0) iChannel = DPRINT_HWDETECT;
285 else if (strcmp(channel, "windows" ) == 0) iChannel = DPRINT_WINDOWS;
286 else if (strcmp(channel, "peloader" ) == 0) iChannel = DPRINT_PELOADER;
287 else if (strcmp(channel, "scsiport" ) == 0) iChannel = DPRINT_SCSIPORT;
288 else if (strcmp(channel, "heap" ) == 0) iChannel = DPRINT_HEAP;
289 else if (strcmp(channel, "all" ) == 0)
290 {
291 int i;
292
293 for(i= 0 ; i < DBG_CHANNELS_COUNT; i++)
294 {
295 if(op==L'+')
296 DbgChannels[i] |= iLevel;
297 else
298 DbgChannels[i] &= ~iLevel;
299 }
300
301 return TRUE;
302 }
303 else return FALSE;
304
305 if (op == L'+')
306 DbgChannels[iChannel] |= iLevel;
307 else
308 DbgChannels[iChannel] &= ~iLevel;
309
310 return TRUE;
311 }
312
313 VOID
314 DbgParseDebugChannels(PCHAR Value)
315 {
316 CHAR *str, *separator, *c, op;
317
318 str = Value;
319
320 do
321 {
322 separator = strchr(str, ',');
323 if (separator != NULL)
324 *separator = '\0';
325
326 c = strchr(str, '+');
327 if (c == NULL)
328 c = strchr(str, '-');
329
330 if (c != NULL)
331 {
332 op = *c;
333 *c = '\0';
334 c++;
335
336 DbgAddDebugChannel(c, str, op);
337 }
338
339 str = separator + 1;
340 } while (separator != NULL);
341 }
342
343 #else
344
345 ULONG
346 DbgPrint(PCCH Format, ...)
347 {
348 return 0;
349 }
350
351 #endif // DBG
352
353 ULONG
354 MsgBoxPrint(const char *Format, ...)
355 {
356 va_list ap;
357 CHAR Buffer[512];
358 ULONG Length;
359
360 va_start(ap, Format);
361
362 /* Construct a string */
363 Length = _vsnprintf(Buffer, 512, Format, ap);
364
365 /* Check if we went past the buffer */
366 if (Length == MAXULONG)
367 {
368 /* Terminate it if we went over-board */
369 Buffer[sizeof(Buffer) - 1] = '\n';
370
371 /* Put maximum */
372 Length = sizeof(Buffer);
373 }
374
375 /* Show it as a message box */
376 UiMessageBox(Buffer);
377
378 /* Cleanup and exit */
379 va_end(ap);
380 return 0;
381 }
382
383 // DECLSPEC_NORETURN
384 VOID
385 NTAPI
386 KeBugCheckEx(
387 IN ULONG BugCheckCode,
388 IN ULONG_PTR BugCheckParameter1,
389 IN ULONG_PTR BugCheckParameter2,
390 IN ULONG_PTR BugCheckParameter3,
391 IN ULONG_PTR BugCheckParameter4)
392 {
393 char Buffer[70];
394 sprintf(Buffer, "*** STOP: 0x%08lX (0x%08lX, 0x%08lX, 0x%08lX, 0x%08lX)",
395 BugCheckCode, BugCheckParameter1, BugCheckParameter2,
396 BugCheckParameter3, BugCheckParameter4);
397 UiMessageBoxCritical(Buffer);
398 ASSERT(FALSE);
399 for (;;);
400 }
401
402 VOID
403 NTAPI
404 RtlAssert(IN PVOID FailedAssertion,
405 IN PVOID FileName,
406 IN ULONG LineNumber,
407 IN PCHAR Message OPTIONAL)
408 {
409 if (Message)
410 {
411 DbgPrint("Assertion \'%s\' failed at %s line %u: %s\n",
412 (PCHAR)FailedAssertion,
413 (PCHAR)FileName,
414 LineNumber,
415 Message);
416 }
417 else
418 {
419 DbgPrint("Assertion \'%s\' failed at %s line %u\n",
420 (PCHAR)FailedAssertion,
421 (PCHAR)FileName,
422 LineNumber);
423 }
424
425 DbgBreakPoint();
426 }
427
428 char *BugCodeStrings[] =
429 {
430 "TEST_BUGCHECK",
431 "MISSING_HARDWARE_REQUIREMENTS",
432 "FREELDR_IMAGE_CORRUPTION",
433 "MEMORY_INIT_FAILURE",
434 };
435
436 ULONG_PTR BugCheckInfo[5];