update for HEAD-2003091401
[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 (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 */