dbf7f352865e5cecc263f25d116af2e7fd024ab9
[reactos.git] / reactos / ntoskrnl / kd / kdebug.c
1 /* $Id: kdebug.c,v 1.54 2004/08/07 03:41:31 sedwards Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/kd/kdebug.c
6 * PURPOSE: Kernel debugger
7 * PROGRAMMER: Eric Kohl (ekohl@abo.rhein-zeitung.de)
8 * UPDATE HISTORY:
9 * 21/10/99: Created
10 */
11
12 #include <ddk/ntddk.h>
13 #include <internal/ntoskrnl.h>
14 #include <internal/kd.h>
15 #include <internal/mm.h>
16 #include <roscfg.h>
17 #include "../dbg/kdb.h"
18 #include <internal/debug.h>
19
20 /* serial debug connection */
21 #define DEFAULT_DEBUG_PORT 2 /* COM2 */
22 #define DEFAULT_DEBUG_COM1_IRQ 4 /* COM1 IRQ */
23 #define DEFAULT_DEBUG_COM2_IRQ 3 /* COM2 IRQ */
24 #define DEFAULT_DEBUG_BAUD_RATE 115200 /* 115200 Baud */
25
26 /* bochs debug output */
27 #define BOCHS_LOGGER_PORT (0xe9)
28
29 /* VARIABLES ***************************************************************/
30
31 BOOLEAN
32 __declspec(dllexport)
33 KdDebuggerEnabled = FALSE; /* EXPORTED */
34
35 BOOLEAN
36 __declspec(dllexport)
37 KdEnteredDebugger = FALSE; /* EXPORTED */
38
39 BOOLEAN
40 __declspec(dllexport)
41 KdDebuggerNotPresent = TRUE; /* EXPORTED */
42
43 ULONG
44 __declspec(dllexport)
45 KiBugCheckData; /* EXPORTED */
46
47 BOOLEAN
48 __declspec(dllexport)
49 KiEnableTimerWatchdog = FALSE; /* EXPORTED */
50
51
52 static BOOLEAN KdpBreakPending = FALSE;
53 ULONG KdDebugState = KD_DEBUG_DISABLED;
54 ULONG KdpPortIrq = 0;
55
56 KD_PORT_INFORMATION GdbPortInfo;
57 KD_PORT_INFORMATION LogPortInfo;
58
59 /* PRIVATE FUNCTIONS ********************************************************/
60
61 static VOID
62 PrintString(char* fmt,...)
63 {
64 char buffer[512];
65 va_list ap;
66
67 va_start(ap, fmt);
68 vsprintf(buffer, fmt, ap);
69 va_end(ap);
70
71 HalDisplayString(buffer);
72 }
73
74
75 VOID INIT_FUNCTION
76 KdInitSystem(ULONG Reserved,
77 PLOADER_PARAMETER_BLOCK LoaderBlock)
78 {
79 KD_PORT_INFORMATION PortInfo;
80 ULONG Value;
81 PCHAR p1, p2;
82
83 #ifdef KDBG
84 /* Initialize runtime debugging if available */
85 DbgRDebugInit();
86 #endif
87
88 #ifdef KDBG
89 /* Initialize the local kernel debugger. */
90 KdDebuggerEnabled = TRUE;
91 KdDebugState |= KD_DEBUG_KDB;
92 #endif
93
94 /* Set debug port default values */
95 PortInfo.ComPort = DEFAULT_DEBUG_PORT;
96 PortInfo.BaudRate = DEFAULT_DEBUG_BAUD_RATE;
97 KdpPortIrq = DEFAULT_DEBUG_COM2_IRQ;
98
99 /* Set serial log port default values */
100 LogPortInfo.ComPort = DEFAULT_DEBUG_PORT;
101 LogPortInfo.BaudRate = DEFAULT_DEBUG_BAUD_RATE;
102
103 /* Parse kernel command line */
104
105 /* Check for 'DEBUGPORT' */
106 p1 = (PCHAR)LoaderBlock->CommandLine;
107 while (p1 && (p2 = strchr(p1, '/')))
108 {
109 p2++;
110 if (!_strnicmp(p2, "DEBUGPORT", 9))
111 {
112 p2 += 9;
113 if (*p2 == '=')
114 {
115 p2++;
116 if (!_strnicmp(p2, "SCREEN", 6))
117 {
118 p2 += 6;
119 KdDebuggerEnabled = TRUE;
120 KdDebugState |= KD_DEBUG_SCREEN;
121 }
122 else if (!_strnicmp(p2, "BOCHS", 5))
123 {
124 p2 += 5;
125 KdDebuggerEnabled = TRUE;
126 KdDebugState |= KD_DEBUG_BOCHS;
127 }
128 else if (!_strnicmp(p2, "GDB", 3))
129 {
130 p2 += 3;
131 KdDebuggerEnabled = TRUE;
132 KdDebugState |= KD_DEBUG_GDB;
133
134 /* Reset port information to defaults */
135 RtlMoveMemory(&GdbPortInfo, &PortInfo, sizeof(KD_PORT_INFORMATION));
136 PortInfo.ComPort = DEFAULT_DEBUG_PORT;
137 PortInfo.BaudRate = DEFAULT_DEBUG_BAUD_RATE;
138 }
139 else if (!_strnicmp(p2, "PICE", 4))
140 {
141 p2 += 4;
142 KdDebuggerEnabled = TRUE;
143 KdDebugState |= KD_DEBUG_PICE;
144 }
145 else if (!_strnicmp(p2, "COM", 3))
146 {
147 p2 += 3;
148 Value = (ULONG)atol(p2);
149 if (Value > 0 && Value < 5)
150 {
151 KdDebuggerEnabled = TRUE;
152 KdDebugState |= KD_DEBUG_SERIAL;
153 LogPortInfo.ComPort = Value;
154 }
155 }
156 else if (!_strnicmp(p2, "BOOTLOG", 4))
157 {
158 p2 += 4;
159 KdDebuggerEnabled = TRUE;
160 KdDebugState |= KD_DEBUG_BOOTLOG;
161 }
162 else if (!_strnicmp(p2, "MDA", 3))
163 {
164 p2 += 3;
165 KdDebuggerEnabled = TRUE;
166 KdDebugState |= KD_DEBUG_MDA;
167 }
168 }
169 }
170 else if (!_strnicmp(p2, "KDSERIAL", 8))
171 {
172 p2 += 8;
173 KdDebuggerEnabled = TRUE;
174 KdDebugState |= KD_DEBUG_SERIAL | KD_DEBUG_KDSERIAL;
175 }
176 else if (!_strnicmp(p2, "KDNOECHO", 8))
177 {
178 p2 += 8;
179 KdDebuggerEnabled = TRUE;
180 KdDebugState |= KD_DEBUG_KDNOECHO;
181 }
182 else if (!_strnicmp(p2, "DEBUG", 5))
183 {
184 p2 += 5;
185 KdDebuggerEnabled = TRUE;
186 KdDebugState |= KD_DEBUG_SERIAL;
187 }
188 else if (!_strnicmp(p2, "NODEBUG", 7))
189 {
190 p2 += 7;
191 KdDebuggerEnabled = FALSE;
192 KdDebugState = KD_DEBUG_DISABLED;
193 }
194 else if (!_strnicmp(p2, "CRASHDEBUG", 10))
195 {
196 p2 += 10;
197 KdDebuggerEnabled = FALSE;
198 KdDebugState = KD_DEBUG_DISABLED;
199 }
200 else if (!_strnicmp(p2, "BREAK", 5))
201 {
202 p2 += 5;
203 KdpBreakPending = TRUE;
204 }
205 else if (!_strnicmp(p2, "COM", 3))
206 {
207 p2 += 3;
208 if ('=' == *p2)
209 {
210 p2++;
211 Value = (ULONG)atol(p2);
212 if (0 < Value && Value < 5)
213 {
214 PortInfo.ComPort = Value;
215 }
216 }
217 }
218 else if (!_strnicmp(p2, "BAUDRATE", 8))
219 {
220 p2 += 8;
221 if ('=' == *p2)
222 {
223 p2++;
224 Value = (ULONG)atol(p2);
225 if (0 < Value)
226 {
227 PortInfo.BaudRate = Value;
228 }
229 }
230 }
231 else if (!_strnicmp(p2, "IRQ", 3))
232 {
233 p2 += 3;
234 if ('=' == *p2)
235 {
236 p2++;
237 Value = (ULONG)atol(p2);
238 if (0 < Value)
239 {
240 KdpPortIrq = Value;
241 }
242 }
243 }
244 #ifdef KDBG
245 else if (!_strnicmp(p2, "PROFILE", 7))
246 {
247 KdbInitProfiling();
248 }
249 #endif /* KDBG */
250 p1 = p2;
251 }
252
253 /* Perform any initialization nescessary */
254 if (KdDebuggerEnabled == TRUE)
255 {
256 if (KdDebugState & KD_DEBUG_GDB)
257 KdPortInitializeEx(&GdbPortInfo, 0, 0);
258
259 if (KdDebugState & KD_DEBUG_SERIAL)
260 KdPortInitializeEx(&LogPortInfo, 0, 0);
261
262 if (KdDebugState & KD_DEBUG_BOOTLOG)
263 DebugLogInit();
264
265 if (KdDebugState & KD_DEBUG_MDA)
266 KdInitializeMda();
267 }
268 }
269
270
271 VOID INIT_FUNCTION
272 KdInit1(VOID)
273 {
274 /* Initialize kernel debugger (phase 0) */
275 if ((KdDebuggerEnabled == TRUE) &&
276 (KdDebugState & KD_DEBUG_GDB))
277 {
278 KdGdbStubInit(0);
279 }
280 }
281
282
283 VOID INIT_FUNCTION
284 KdInit2(VOID)
285 {
286 /* Initialize kernel debugger (phase 1) */
287 if ((KdDebuggerEnabled == TRUE) &&
288 (KdDebugState & KD_DEBUG_GDB))
289 {
290 KdGdbStubInit(1);
291 }
292 }
293
294
295 VOID INIT_FUNCTION
296 KdInit3(VOID)
297 {
298 /* Print some information */
299 if (KdDebuggerEnabled == TRUE)
300 {
301 if (KdDebugState & KD_DEBUG_GDB)
302 PrintString("\n GDB debugging enabled. COM%ld %ld Baud\n\n",
303 GdbPortInfo.ComPort, GdbPortInfo.BaudRate);
304
305 if (KdDebugState & KD_DEBUG_PICE)
306 PrintString("\n Private ICE debugger enabled\n\n");
307
308 if (KdDebugState & KD_DEBUG_SCREEN)
309 PrintString("\n Screen debugging enabled\n\n");
310
311 if (KdDebugState & KD_DEBUG_BOCHS)
312 PrintString("\n Bochs debugging enabled\n\n");
313
314 if (KdDebugState & KD_DEBUG_SERIAL)
315 PrintString("\n Serial debugging enabled. COM%ld %ld Baud\n\n",
316 LogPortInfo.ComPort, LogPortInfo.BaudRate);
317
318 if (KdDebugState & KD_DEBUG_BOOTLOG)
319 PrintString("\n File log debugging enabled\n\n");
320 if (KdDebugState & KD_DEBUG_MDA)
321 PrintString("\n MDA debugging enabled\n\n");
322 }
323 }
324
325
326 VOID
327 KdSerialDebugPrint (LPSTR Message)
328 {
329 PCHAR pch = (PCHAR) Message;
330
331 while (*pch != 0)
332 {
333 if (*pch == '\n')
334 {
335 KdPortPutByteEx (&LogPortInfo, '\r');
336 }
337 KdPortPutByteEx (&LogPortInfo, *pch);
338 pch++;
339 }
340 }
341
342
343 VOID
344 KdBochsDebugPrint(IN LPSTR Message)
345 {
346 while (*Message != 0)
347 {
348 if (*Message == '\n')
349 {
350 WRITE_PORT_UCHAR((PUCHAR)BOCHS_LOGGER_PORT, '\r');
351 }
352 WRITE_PORT_UCHAR((PUCHAR)BOCHS_LOGGER_PORT, *Message);
353 Message++;
354 }
355 }
356
357
358 ULONG
359 KdpPrintString(PANSI_STRING String)
360 {
361 PCH pch = String->Buffer;
362
363 if (KdDebugState & KD_DEBUG_GDB)
364 KdGdbDebugPrint(pch);
365
366 if (KdDebugState & KD_DEBUG_SCREEN)
367 HalDisplayString(pch);
368
369 if (KdDebugState & KD_DEBUG_SERIAL)
370 KdSerialDebugPrint(pch);
371
372 if (KdDebugState & KD_DEBUG_BOCHS)
373 KdBochsDebugPrint(pch);
374
375 if (KdDebugState & KD_DEBUG_BOOTLOG)
376 DebugLogWrite(pch);
377
378 if (KdDebugState & KD_DEBUG_MDA)
379 KdPrintMda(pch);
380
381 return((ULONG)String->Length);
382 }
383
384 /* PUBLIC FUNCTIONS *********************************************************/
385
386 /* NTOSKRNL.KdPollBreakIn */
387
388 /*
389 * @unimplemented
390 */
391 VOID
392 STDCALL
393 KdDisableDebugger(
394 VOID
395 )
396 {
397 UNIMPLEMENTED;
398 }
399
400 /*
401 * @unimplemented
402 */
403 VOID
404 STDCALL
405 KdEnableDebugger (
406 VOID
407 )
408 {
409 UNIMPLEMENTED;
410 }
411
412 /*
413 * @unimplemented
414 */
415 BOOLEAN
416 STDCALL
417 KeIsAttachedProcess(
418 VOID
419 )
420 {
421 UNIMPLEMENTED;
422 return FALSE;
423 }
424
425 /*
426 * @implemented
427 */
428 BOOLEAN STDCALL
429 KdPollBreakIn(VOID)
430 {
431 if ((!KdDebuggerEnabled) || (!(KdDebugState & KD_DEBUG_SERIAL)))
432 return FALSE;
433 return KdpBreakPending;
434 }
435
436 /*
437 * @implemented
438 */
439 VOID STDCALL
440 KeEnterKernelDebugger(VOID)
441 {
442 HalDisplayString("\n\n *** Entered kernel debugger ***\n");
443
444 for (;;)
445 {
446 #if defined(__GNUC__)
447 __asm__("hlt\n\t");
448 #elif defined(_MSC_VER)
449 __asm hlt
450 #else
451 #error Unknown compiler for inline assembler
452 #endif
453 }
454 }
455
456 VOID STDCALL
457 KdSystemDebugControl(ULONG Code)
458 {
459 extern VOID PsDumpThreads(BOOLEAN IncludeSystem);
460
461 /* A - Dump the entire contents of the non-paged pool. */
462 if (Code == 0)
463 {
464 MiDebugDumpNonPagedPool(FALSE);
465 }
466 /* B - Bug check the system. */
467 else if (Code == 1)
468 {
469 KEBUGCHECK(0xDEADDEAD);
470 }
471 /*
472 * C - Dump statistics about the distribution of tagged blocks in
473 * the non-paged pool.
474 */
475 else if (Code == 2)
476 {
477 MiDebugDumpNonPagedPoolStats(FALSE);
478 }
479 /*
480 * D - Dump the blocks created in the non-paged pool since the last
481 * SysRq + D and SysRq + E command.
482 */
483 else if (Code == 3)
484 {
485 MiDebugDumpNonPagedPool(TRUE);
486 }
487 /* E - Dump statistics about the tags of newly created blocks. */
488 else if (Code == 4)
489 {
490 MiDebugDumpNonPagedPoolStats(TRUE);
491 }
492 /* F */
493 else if (Code == 5)
494 {
495 PsDumpThreads(TRUE);
496 }
497 /* G */
498 else if (Code == 6)
499 {
500 PsDumpThreads(FALSE);
501 }
502 /* H */
503 else if (Code == 7)
504 {
505 }
506 /* I */
507 else if (Code == 8)
508 {
509 }
510 /* J */
511 else if (Code == 9)
512 {
513 }
514 /* K - Enter the system debugger. */
515 else if (Code == 10)
516 {
517 #ifdef KDBG
518 KdbEnter();
519 #else /* KDBG */
520 DbgPrint("No local kernel debugger\n");
521 #endif /* not KDBG */
522 }
523 }
524
525 /*
526 * @unimplemented
527 */
528 NTSTATUS
529 STDCALL
530 KdPowerTransition(
531 ULONG PowerState
532 )
533 {
534 UNIMPLEMENTED;
535 return STATUS_NOT_IMPLEMENTED;
536 }
537
538 /* Support routines for the GDB stubs */
539
540 VOID
541 KdPutChar(UCHAR Value)
542 {
543 KdPortPutByteEx (&GdbPortInfo, Value);
544 }
545
546
547 UCHAR
548 KdGetChar(VOID)
549 {
550 UCHAR Value;
551
552 while (!KdPortGetByteEx (&GdbPortInfo, &Value));
553
554 return Value;
555 }
556
557 /* EOF */