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