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