branch update for HEAD-2003021201
[reactos.git] / 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  * 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 (Value > 0 && 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 (Value > 0)
201                         {
202                           PortInfo.BaudRate = Value;
203                         }
204             }
205           else if (!_strnicmp(p2, "IRQ", 3))
206             {
207               p2 += 3;
208               if (*p2 != '=')
209                 {
210                   p2++;
211                   Value = (ULONG)atol(p2);
212                   if (Value > 0)
213                     {
214                       KdpPortIrq = Value;
215                     }
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   /* Print some information */
229   if (KdDebuggerEnabled == TRUE)
230     {
231       if (KdDebugState & KD_DEBUG_GDB)
232             PrintString("\n   GDB debugging enabled. COM%ld %ld Baud\n\n",
233                         GdbPortInfo.ComPort, GdbPortInfo.BaudRate);
234           
235       if (KdDebugState & KD_DEBUG_PICE)
236             PrintString("\n   Private ICE debugger enabled\n\n");
237
238       if (KdDebugState & KD_DEBUG_SCREEN)
239             PrintString("\n   Screen debugging enabled\n\n");
240
241       if (KdDebugState & KD_DEBUG_BOCHS)
242             PrintString("\n   Bochs debugging enabled\n\n");
243
244       if (KdDebugState & KD_DEBUG_SERIAL)
245             PrintString("\n   Serial debugging enabled. COM%ld %ld Baud\n\n",
246                         LogPortInfo.ComPort, LogPortInfo.BaudRate);
247
248       if (KdDebugState & KD_DEBUG_FILELOG)
249             PrintString("\n   File log debugging enabled\n\n");
250       if (KdDebugState & KD_DEBUG_MDA)
251             PrintString("\n   MDA debugging enabled\n\n");
252     }
253
254   /* Perform any initialization nescessary */
255   if (KdDebuggerEnabled == TRUE)
256     {
257       if (KdDebugState & KD_DEBUG_GDB)
258             KdPortInitializeEx(&GdbPortInfo, 0, 0);
259
260       if (KdDebugState & KD_DEBUG_SERIAL)
261             KdPortInitializeEx(&LogPortInfo, 0, 0);
262
263       if (KdDebugState & KD_DEBUG_FILELOG)
264             DebugLogInit();
265
266       if (KdDebugState & KD_DEBUG_MDA)
267             KdInitializeMda();
268     }
269 }
270
271
272 VOID
273 KdInit1(VOID)
274 {
275   /* Initialize kernel debugger (phase 0) */
276   if ((KdDebuggerEnabled == TRUE) &&
277       (KdDebugState & KD_DEBUG_GDB))
278     {
279       KdGdbStubInit(0);
280     }
281 }
282
283
284 VOID 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 VOID
295 KdSerialDebugPrint (LPSTR Message)
296 {
297   PCHAR pch = (PCHAR) Message;
298
299   while (*pch != 0)
300     {
301       if (*pch == '\n')
302         {
303           KdPortPutByteEx (&LogPortInfo, '\r');
304         }
305         KdPortPutByteEx (&LogPortInfo, *pch);
306         pch++;
307     }
308 }
309
310
311 VOID
312 KdBochsDebugPrint(IN LPSTR  Message)
313 {
314         while (*Message != 0)
315           {
316             if (*Message == '\n')
317               {
318                 WRITE_PORT_UCHAR((PUCHAR)BOCHS_LOGGER_PORT, '\r');
319               }
320             WRITE_PORT_UCHAR((PUCHAR)BOCHS_LOGGER_PORT, *Message);
321             Message++;
322           }
323 }
324
325
326 ULONG
327 KdpPrintString(PANSI_STRING String)
328 {
329         PCH pch = String->Buffer;
330
331         if (KdDebugState & KD_DEBUG_GDB)
332                 KdGdbDebugPrint(pch);
333
334         if (KdDebugState & KD_DEBUG_SCREEN)
335                 HalDisplayString(pch);
336
337         if (KdDebugState & KD_DEBUG_SERIAL)
338                 KdSerialDebugPrint(pch);
339
340         if (KdDebugState & KD_DEBUG_BOCHS)
341                 KdBochsDebugPrint(pch);
342
343         if (KdDebugState & KD_DEBUG_FILELOG)
344                 DebugLogWrite(pch);
345
346         if (KdDebugState & KD_DEBUG_MDA)
347                 KdPrintMda(pch);
348
349         return((ULONG)String->Length);
350 }
351
352 /* PUBLIC FUNCTIONS *********************************************************/
353
354 /* NTOSKRNL.KdPollBreakIn */
355
356 BOOLEAN STDCALL
357 KdPollBreakIn(VOID)
358 {
359   if ((!KdDebuggerEnabled) || (!(KdDebugState & KD_DEBUG_SERIAL)))
360     return FALSE;
361   return KdpBreakPending;
362 }
363
364 VOID STDCALL
365 KeEnterKernelDebugger(VOID)
366 {
367   HalDisplayString("\n\n *** Entered kernel debugger ***\n");
368
369   for (;;)
370     __asm__("hlt\n\t");
371 }
372
373 VOID STDCALL
374 KdSystemDebugControl(ULONG Code)
375 {
376   extern VOID PsDumpThreads(BOOLEAN IncludeSystem);
377
378   /* A - Dump the entire contents of the non-paged pool. */
379   if (Code == 0)
380     {
381       MiDebugDumpNonPagedPool(FALSE);
382     }
383   /* B - Bug check the system. */
384   else if (Code == 1)
385     {
386       KeBugCheck(0);
387     }
388   /* 
389    * C -  Dump statistics about the distribution of tagged blocks in 
390    *      the non-paged pool.
391    */
392   else if (Code == 2)
393     {
394       MiDebugDumpNonPagedPoolStats(FALSE);
395     }
396   /* 
397    * D - Dump the blocks created in the non-paged pool since the last
398    * SysRq + D and SysRq + E command.
399    */
400   else if (Code == 3)
401     {
402       MiDebugDumpNonPagedPool(TRUE);
403     }
404   /* E - Dump statistics about the tags of newly created blocks. */
405   else if (Code == 4)
406     {
407       MiDebugDumpNonPagedPoolStats(TRUE);
408     }
409   /* F */
410   else if (Code == 5)
411     {
412       PsDumpThreads(TRUE);
413     }
414   /* G */
415   else if (Code == 6)
416     {
417       PsDumpThreads(FALSE);
418     }
419   /* H */
420   else if (Code == 7)
421     {
422     }
423   /* I */
424   else if (Code == 8)
425     {
426     }
427   /* J */
428   else if (Code == 9)
429     {
430     }
431   /* K - Enter the system debugger. */
432   else if (Code == 10)
433     {
434 #ifdef KDBG
435       KdbEnter();
436 #else /* KDBG */
437       DbgPrint("No local kernel debugger\n");
438 #endif /* not KDBG */
439     }
440 }
441
442
443 /* Support routines for the GDB stubs */
444
445 VOID
446 KdPutChar(UCHAR Value)
447 {
448   KdPortPutByteEx (&GdbPortInfo, Value);
449 }
450
451
452 UCHAR
453 KdGetChar(VOID)
454 {
455   UCHAR Value;
456
457   while (!KdPortGetByteEx (&GdbPortInfo, &Value));
458
459   return Value;
460 }
461
462 /* EOF */