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