06fb0709ed175c81dac06bbe8797a97b69222689
[tpg/acess2.git] / Kernel / debug.c
1 /*
2  * AcessOS Microkernel Version
3  * debug.c
4  */
5 #include <acess.h>
6 #include <stdarg.h>
7
8 #define DEBUG_TO_E9     1
9 #define DEBUG_TO_SERIAL 1
10 #define SERIAL_PORT     0x3F8
11 #define GDB_SERIAL_PORT 0x2F8
12 #define DEBUG_USE_VSNPRINTF     0
13 #define DEBUG_MAX_LINE_LEN      256
14
15 // === IMPORTS ===
16 extern void Threads_Dump(void);
17 extern void     KernelPanic_SetMode(void);
18 extern void     KernelPanic_PutChar(char Ch);
19
20 // === PROTOTYPES ===
21  int    putDebugChar(char ch);
22  int    getDebugChar();
23 static void     Debug_Putchar(char ch);
24 static void     Debug_Puts(char *Str);
25 void    Debug_Fmt(const char *format, va_list args);
26
27 // === GLOBALS ===
28  int    gDebug_Level = 0;
29  int    giDebug_KTerm = -1;
30  int    gbDebug_SerialSetup = 0;
31  int    gbGDB_SerialSetup = 0;
32  int    gbDebug_IsKPanic = 0;
33 volatile int    gbInPutChar = 0;
34
35 // === CODE ===
36 int putDebugChar(char ch)
37 {
38         if(!gbGDB_SerialSetup) {
39                 outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
40                 outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
41                 outb(GDB_SERIAL_PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
42                 outb(GDB_SERIAL_PORT + 1, 0x00);    //                  (hi byte)
43                 outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
44                 outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
45                 outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
46                 gbDebug_SerialSetup = 1;
47         }
48         while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
49         outb(GDB_SERIAL_PORT, ch);
50         return 0;
51 }
52 int getDebugChar()
53 {
54         if(!gbGDB_SerialSetup) {
55                 outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
56                 outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
57                 outb(GDB_SERIAL_PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
58                 outb(GDB_SERIAL_PORT + 1, 0x00);    //                  (hi byte)
59                 outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
60                 outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
61                 outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
62                 gbDebug_SerialSetup = 1;
63         }
64         while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0)     ;
65         return inb(GDB_SERIAL_PORT);
66 }
67
68 static void Debug_Putchar(char ch)
69 {
70         #if DEBUG_TO_E9
71         __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
72         #endif
73         
74         #if DEBUG_TO_SERIAL
75         if(!gbDebug_SerialSetup) {
76                 outb(SERIAL_PORT + 1, 0x00);    // Disable all interrupts
77                 outb(SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
78                 outb(SERIAL_PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
79                 outb(SERIAL_PORT + 1, 0x00);    //                  (hi byte)
80                 outb(SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
81                 outb(SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
82                 outb(SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
83                 gbDebug_SerialSetup = 1;
84         }
85         while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
86         outb(SERIAL_PORT, ch);
87         #endif
88         
89         if( !gbDebug_IsKPanic )
90         {
91                 if(gbInPutChar) return ;
92                 gbInPutChar = 1;
93                 if(giDebug_KTerm != -1)
94                         VFS_Write(giDebug_KTerm, 1, &ch);
95                 gbInPutChar = 0;
96         }
97         else
98                 KernelPanic_PutChar(ch);
99 }
100
101 static void Debug_Puts(char *Str)
102 {
103          int    len = 0;
104         while( *Str )
105         {
106                 #if DEBUG_TO_E9
107                 __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a" ((Uint8)*Str) );
108                 #endif
109                 
110                 #if DEBUG_TO_SERIAL
111                 if(!gbDebug_SerialSetup) {
112                         outb(SERIAL_PORT + 1, 0x00);    // Disable all interrupts
113                         outb(SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
114                         outb(SERIAL_PORT + 0, 0x03);    // Set divisor to 3 (lo byte) 38400 baud
115                         outb(SERIAL_PORT + 1, 0x00);    //                  (hi byte)
116                         outb(SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
117                         outb(SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
118                         outb(SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
119                         gbDebug_SerialSetup = 1;
120                 }
121                 while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
122                 outb(SERIAL_PORT, *Str);
123                 #endif
124                 
125                 if( gbDebug_IsKPanic )
126                         KernelPanic_PutChar(*Str);
127                 len ++;
128                 Str ++;
129         }
130         
131         Str -= len;
132         
133         if( !gbDebug_IsKPanic && giDebug_KTerm != -1)
134         {
135                 if(gbInPutChar) return ;
136                 gbInPutChar = 1;
137                 VFS_Write(giDebug_KTerm, len, Str);
138                 gbInPutChar = 0;
139         }
140 }
141
142 void Debug_Fmt(const char *format, va_list args)
143 {
144         #if DEBUG_USE_VSNPRINTF
145         char    buf[DEBUG_MAX_LINE_LEN];
146          int    len;
147         buf[DEBUG_MAX_LINE_LEN-1] = 0;
148         len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
149         //if( len < DEBUG_MAX_LINE )
150                 // do something
151         Debug_Puts(buf);
152         return ;
153         #else
154         char    c, pad = ' ';
155          int    minSize = 0, len;
156         char    tmpBuf[34];     // For Integers
157         char    *p = NULL;
158          int    isLongLong = 0;
159         Uint64  arg;
160          int    bPadLeft = 0;
161
162         while((c = *format++) != 0)
163         {
164                 // Non control character
165                 if( c != '%' ) {
166                         Debug_Putchar(c);
167                         continue;
168                 }
169
170                 c = *format++;
171
172                 // Literal %
173                 if(c == '%') {
174                         Debug_Putchar('%');
175                         continue;
176                 }
177
178                 // Pointer
179                 if(c == 'p') {
180                         Uint    ptr = va_arg(args, Uint);
181                         Debug_Putchar('*');     Debug_Putchar('0');     Debug_Putchar('x');
182                         p = tmpBuf;
183                         itoa(p, ptr, 16, BITS/4, '0');
184                         goto printString;
185                 }
186
187                 // Get Argument
188                 arg = va_arg(args, Uint);
189
190                 // - Padding Side Flag
191                 if(c == '+') {
192                         bPadLeft = 1;
193                         c = *format++;
194                 }
195
196                 // Padding
197                 if(c == '0') {
198                         pad = '0';
199                         c = *format++;
200                 } else
201                         pad = ' ';
202
203                 // Minimum length
204                 minSize = 1;
205                 if('1' <= c && c <= '9')
206                 {
207                         minSize = 0;
208                         while('0' <= c && c <= '9')
209                         {
210                                 minSize *= 10;
211                                 minSize += c - '0';
212                                 c = *format++;
213                         }
214                 }
215
216                 // Long (default)
217                 isLongLong = 0;
218                 if(c == 'l') {
219                         c = *format++;
220                         if(c == 'l') {
221                                 #if BITS == 32
222                                 arg |= va_arg(args, Uint);
223                                 #endif
224                                 c = *format++;
225                                 isLongLong = 1;
226                         }
227                 }
228
229                 p = tmpBuf;
230                 switch (c) {
231                 case 'd':
232                 case 'i':
233                         if( (isLongLong && arg >> 63) || (!isLongLong && arg >> 31) ) {
234                                 Debug_Putchar('-');
235                                 arg = -arg;
236                         }
237                         itoa(p, arg, 10, minSize, pad);
238                         goto printString;
239                 case 'u':
240                         itoa(p, arg, 10, minSize, pad);
241                         goto printString;
242                 case 'x':
243                         itoa(p, arg, 16, minSize, pad);
244                         goto printString;
245                 case 'o':
246                         itoa(p, arg, 8, minSize, pad);
247                         goto printString;
248                 case 'b':
249                         itoa(p, arg, 2, minSize, pad);
250                         goto printString;
251
252                 printString:
253                         if(!p)          p = "(null)";
254                         while(*p)       Debug_Putchar(*p++);
255                         break;
256
257                 case 'B':       //Boolean
258                         if(arg) Debug_Puts("True");
259                         else    Debug_Puts("False");
260                         break;
261
262                 case 's':
263                         p = (char*)(Uint)arg;
264                         if(!p)          p = "(null)";
265                         len = strlen(p);
266                         if( !bPadLeft ) while(len++ < minSize)  Debug_Putchar(pad);
267                         while(*p)       Debug_Putchar(*p++);
268                         if( bPadLeft )  while(len++ < minSize)  Debug_Putchar(pad);
269                         break;
270
271                 // Single Character / Array
272                 case 'c':
273                         if(minSize == 1) {
274                                 Debug_Putchar(arg);
275                                 break;
276                         }
277                         p = (char*)(Uint)arg;
278                         if(!p)  goto printString;
279                         while(minSize--)        Debug_Putchar(*p++);
280                         break;
281
282                 default:
283                         Debug_Putchar(arg);
284                         break;
285                 }
286     }
287     #endif
288 }
289
290 void Debug_KernelPanic()
291 {
292         gbDebug_IsKPanic = 1;
293         KernelPanic_SetMode();
294 }
295
296 /**
297  * \fn void LogF(char *Msg, ...)
298  */
299 void LogF(char *Fmt, ...)
300 {
301         va_list args;
302
303         va_start(args, Fmt);
304
305         Debug_Fmt(Fmt, args);
306
307         va_end(args);
308 }
309 /**
310  * \fn void Log(char *Msg, ...)
311  */
312 void Log(char *Fmt, ...)
313 {
314         va_list args;
315
316         Debug_Puts("Log: ");
317         va_start(args, Fmt);
318         Debug_Fmt(Fmt, args);
319         va_end(args);
320         Debug_Putchar('\n');
321 }
322 void Warning(char *Fmt, ...)
323 {
324         va_list args;
325         Debug_Puts("Warning: ");
326         va_start(args, Fmt);
327         Debug_Fmt(Fmt, args);
328         va_end(args);
329         Debug_Putchar('\n');
330 }
331 void Panic(char *Fmt, ...)
332 {
333         va_list args;
334         
335         Debug_KernelPanic();
336         
337         Debug_Puts("Panic: ");
338         va_start(args, Fmt);
339         Debug_Fmt(Fmt, args);
340         va_end(args);
341         Debug_Putchar('\n');
342
343         Threads_Dump();
344
345         __asm__ __volatile__ ("xchg %bx, %bx");
346         __asm__ __volatile__ ("cli;\n\thlt");
347         for(;;) __asm__ __volatile__ ("hlt");
348 }
349
350 void Debug_SetKTerminal(char *File)
351 {
352          int    tmp;
353         if(giDebug_KTerm != -1) {
354                 tmp = giDebug_KTerm;
355                 giDebug_KTerm = -1;
356                 VFS_Close(tmp);
357         }
358         tmp = VFS_Open(File, VFS_OPENFLAG_WRITE);
359         Log_Log("Debug", "Opened '%s' as 0x%x", File, tmp);
360         giDebug_KTerm = tmp;
361         Log_Log("Debug", "Returning to %p", __builtin_return_address(0));
362 }
363
364 void Debug_Enter(char *FuncName, char *ArgTypes, ...)
365 {
366         va_list args;
367          int    i = gDebug_Level ++;
368          int    pos;
369
370         va_start(args, ArgTypes);
371
372         while(i--)      Debug_Putchar(' ');
373
374         Debug_Puts(FuncName);   Debug_Puts(": (");
375
376         while(*ArgTypes)
377         {
378                 pos = strpos(ArgTypes, ' ');
379                 if(pos != -1)   ArgTypes[pos] = '\0';
380                 if(pos == -1 || pos > 1) {
381                         Debug_Puts(ArgTypes+1);
382                         Debug_Putchar('=');
383                 }
384                 if(pos != -1)   ArgTypes[pos] = ' ';
385                 switch(*ArgTypes)
386                 {
387                 case 'p':       Debug_Fmt("%p", args);  break;
388                 case 's':       Debug_Fmt("'%s'", args);        break;
389                 case 'i':       Debug_Fmt("%i", args);  break;
390                 case 'u':       Debug_Fmt("%u", args);  break;
391                 case 'x':       Debug_Fmt("0x%x", args);        break;
392                 case 'b':       Debug_Fmt("0b%b", args);        break;
393                 case 'X':       Debug_Fmt("0x%llx", args);      break;  // Extended (64-Bit)
394                 case 'B':       Debug_Fmt("0b%llb", args);      break;  // Extended (64-Bit)
395                 }
396                 if(pos != -1) {
397                         Debug_Putchar(',');     Debug_Putchar(' ');
398                 }
399
400                 if(pos == -1)   break;
401                 ArgTypes = &ArgTypes[pos+1];
402         }
403
404         va_end(args);
405         Debug_Putchar(')');     Debug_Putchar('\n');
406 }
407
408 void Debug_Log(char *FuncName, char *Fmt, ...)
409 {
410         va_list args;
411          int    i = gDebug_Level;
412
413         va_start(args, Fmt);
414
415         while(i--)      Debug_Putchar(' ');
416
417         Debug_Puts(FuncName);   Debug_Puts(": ");
418         Debug_Fmt(Fmt, args);
419
420         va_end(args);
421         Debug_Putchar('\n');
422 }
423
424 void Debug_Leave(char *FuncName, char RetType, ...)
425 {
426         va_list args;
427          int    i = --gDebug_Level;
428
429         va_start(args, RetType);
430
431         if( i == -1 ) {
432                 gDebug_Level = 0;
433                 i = 0;
434         }
435         // Indenting
436         while(i--)      Debug_Putchar(' ');
437
438         Debug_Puts(FuncName);   Debug_Puts(": RETURN");
439
440         // No Return
441         if(RetType == '-') {
442                 Debug_Putchar('\n');
443                 return;
444         }
445
446         Debug_Putchar(' ');
447         switch(RetType)
448         {
449         case 'n':       Debug_Puts("NULL");     break;
450         case 'p':       Debug_Fmt("%p", args);  break;
451         case 's':       Debug_Fmt("'%s'", args);        break;
452         case 'i':       Debug_Fmt("%i", args);  break;
453         case 'u':       Debug_Fmt("%u", args);  break;
454         case 'x':       Debug_Fmt("0x%x", args);        break;
455         // Extended (64-Bit)
456         case 'X':       Debug_Fmt("0x%llx", args);      break;
457         }
458         Debug_Putchar('\n');
459
460         va_end(args);
461 }
462
463 void Debug_HexDump(char *Header, void *Data, Uint Length)
464 {
465         Uint8   *cdat = Data;
466         Uint    pos = 0;
467         Debug_Puts(Header);
468         LogF(" (Hexdump of %p)\n", Data);
469
470         while(Length >= 16)
471         {
472                 #define CH(n)   ((' '<=cdat[(n)]&&cdat[(n)]<=0x7F) ? cdat[(n)] : '.')
473                 Log("%04x: %02x %02x %02x %02x %02x %02x %02x %02x"
474                         " %02x %02x %02x %02x %02x %02x %02x %02x"
475                         "  %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c",
476                         pos,
477                         cdat[0], cdat[1], cdat[2], cdat[3], cdat[4], cdat[5], cdat[6], cdat[7],
478                         cdat[8], cdat[9], cdat[10], cdat[11], cdat[12], cdat[13], cdat[14], cdat[15],
479                         CH(0),  CH(1),  CH(2),  CH(3),  CH(4),  CH(5),  CH(6),  CH(7),
480                         CH(8),  CH(9),  CH(10), CH(11), CH(12), CH(13), CH(14), CH(15)
481                         );
482                 Length -= 16;
483                 cdat += 16;
484                 pos += 16;
485         }
486
487         LogF("Log: %04x: ", pos);
488         while(Length)
489         {
490                 Uint    byte = *cdat;
491                 LogF("%02x ", byte);
492                 Length--;
493                 cdat ++;
494         }
495         Debug_Putchar('\n');
496 }
497
498 // --- EXPORTS ---
499 EXPORT(Log);
500 EXPORT(Warning);
501 EXPORT(Debug_Enter);
502 EXPORT(Debug_Log);
503 EXPORT(Debug_Leave);

UCC git Repository :: git.ucc.asn.au