Altered debug print function to use vsnprintf and to use Debug_Puts instead of Debug_...
[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     1
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         len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
148         //if( len < DEBUG_MAX_LINE )
149                 // do something
150         Debug_Puts(buf);
151         return ;
152         #else
153         char    c, pad = ' ';
154          int    minSize = 0, len;
155         char    tmpBuf[34];     // For Integers
156         char    *p = NULL;
157          int    isLongLong = 0;
158         Uint64  arg;
159          int    bPadLeft = 0;
160
161         while((c = *format++) != 0)
162         {
163                 // Non control character
164                 if( c != '%' ) {
165                         Debug_Putchar(c);
166                         continue;
167                 }
168
169                 c = *format++;
170
171                 // Literal %
172                 if(c == '%') {
173                         Debug_Putchar('%');
174                         continue;
175                 }
176
177                 // Pointer
178                 if(c == 'p') {
179                         Uint    ptr = va_arg(*args, Uint);
180                         Debug_Putchar('*');     Debug_Putchar('0');     Debug_Putchar('x');
181                         p = tmpBuf;
182                         itoa(p, ptr, 16, BITS/4, '0');
183                         goto printString;
184                 }
185
186                 // Get Argument
187                 arg = va_arg(*args, Uint);
188
189                 // - Padding Side Flag
190                 if(c == '+') {
191                         bPadLeft = 1;
192                         c = *format++;
193                 }
194
195                 // Padding
196                 if(c == '0') {
197                         pad = '0';
198                         c = *format++;
199                 } else
200                         pad = ' ';
201
202                 // Minimum length
203                 minSize = 1;
204                 if('1' <= c && c <= '9')
205                 {
206                         minSize = 0;
207                         while('0' <= c && c <= '9')
208                         {
209                                 minSize *= 10;
210                                 minSize += c - '0';
211                                 c = *format++;
212                         }
213                 }
214
215                 // Long (default)
216                 isLongLong = 0;
217                 if(c == 'l') {
218                         c = *format++;
219                         if(c == 'l') {
220                                 #if BITS == 32
221                                 arg |= va_arg(*args, Uint);
222                                 #endif
223                                 c = *format++;
224                                 isLongLong = 1;
225                         }
226                 }
227
228                 p = tmpBuf;
229                 switch (c) {
230                 case 'd':
231                 case 'i':
232                         if( (isLongLong && arg >> 63) || (!isLongLong && arg >> 31) ) {
233                                 Debug_Putchar('-');
234                                 arg = -arg;
235                         }
236                         itoa(p, arg, 10, minSize, pad);
237                         goto printString;
238                 case 'u':
239                         itoa(p, arg, 10, minSize, pad);
240                         goto printString;
241                 case 'x':
242                         itoa(p, arg, 16, minSize, pad);
243                         goto printString;
244                 case 'o':
245                         itoa(p, arg, 8, minSize, pad);
246                         goto printString;
247                 case 'b':
248                         itoa(p, arg, 2, minSize, pad);
249                         goto printString;
250
251                 printString:
252                         if(!p)          p = "(null)";
253                         while(*p)       Debug_Putchar(*p++);
254                         break;
255
256                 case 'B':       //Boolean
257                         if(arg) Debug_Puts("True");
258                         else    Debug_Puts("False");
259                         break;
260
261                 case 's':
262                         p = (char*)(Uint)arg;
263                         if(!p)          p = "(null)";
264                         len = strlen(p);
265                         if( !bPadLeft ) while(len++ < minSize)  Debug_Putchar(pad);
266                         while(*p)       Debug_Putchar(*p++);
267                         if( bPadLeft )  while(len++ < minSize)  Debug_Putchar(pad);
268                         break;
269
270                 // Single Character / Array
271                 case 'c':
272                         if(minSize == 1) {
273                                 Debug_Putchar(arg);
274                                 break;
275                         }
276                         p = (char*)(Uint)arg;
277                         if(!p)  goto printString;
278                         while(minSize--)        Debug_Putchar(*p++);
279                         break;
280
281                 default:
282                         Debug_Putchar(arg);
283                         break;
284                 }
285     }
286     #endif
287 }
288
289 void Debug_KernelPanic()
290 {
291         gbDebug_IsKPanic = 1;
292         KernelPanic_SetMode();
293 }
294
295 /**
296  * \fn void LogF(char *Msg, ...)
297  */
298 void LogF(char *Fmt, ...)
299 {
300         va_list args;
301
302         va_start(args, Fmt);
303
304         Debug_Fmt(Fmt, args);
305
306         va_end(args);
307 }
308 /**
309  * \fn void Log(char *Msg, ...)
310  */
311 void Log(char *Fmt, ...)
312 {
313         va_list args;
314
315         Debug_Puts("Log: ");
316         va_start(args, Fmt);
317         Debug_Fmt(Fmt, args);
318         va_end(args);
319         Debug_Putchar('\n');
320 }
321 void Warning(char *Fmt, ...)
322 {
323         va_list args;
324         Debug_Puts("Warning: ");
325         va_start(args, Fmt);
326         Debug_Fmt(Fmt, args);
327         va_end(args);
328         Debug_Putchar('\n');
329 }
330 void Panic(char *Fmt, ...)
331 {
332         va_list args;
333         
334         Debug_KernelPanic();
335         
336         Debug_Puts("Panic: ");
337         va_start(args, Fmt);
338         Debug_Fmt(Fmt, args);
339         va_end(args);
340         Debug_Putchar('\n');
341
342         Threads_Dump();
343
344         __asm__ __volatile__ ("xchg %bx, %bx");
345         __asm__ __volatile__ ("cli;\n\thlt");
346         for(;;) __asm__ __volatile__ ("hlt");
347 }
348
349 void Debug_SetKTerminal(char *File)
350 {
351          int    tmp;
352         if(giDebug_KTerm != -1) {
353                 tmp = giDebug_KTerm;
354                 giDebug_KTerm = -1;
355                 VFS_Close(tmp);
356         }
357         tmp = VFS_Open(File, VFS_OPENFLAG_WRITE);
358         Log_Log("Debug", "Opened '%s' as 0x%x", File, tmp);
359         giDebug_KTerm = tmp;
360         Log_Log("Debug", "Returning to %p", __builtin_return_address(0));
361 }
362
363 void Debug_Enter(char *FuncName, char *ArgTypes, ...)
364 {
365         va_list args;
366          int    i = gDebug_Level ++;
367          int    pos;
368
369         va_start(args, ArgTypes);
370
371         while(i--)      Debug_Putchar(' ');
372
373         Debug_Puts(FuncName);   Debug_Puts(": (");
374
375         while(*ArgTypes)
376         {
377                 pos = strpos(ArgTypes, ' ');
378                 if(pos != -1)   ArgTypes[pos] = '\0';
379                 if(pos == -1 || pos > 1) {
380                         Debug_Puts(ArgTypes+1);
381                         Debug_Putchar('=');
382                 }
383                 if(pos != -1)   ArgTypes[pos] = ' ';
384                 switch(*ArgTypes)
385                 {
386                 case 'p':       Debug_Fmt("%p", args);  break;
387                 case 's':       Debug_Fmt("'%s'", args);        break;
388                 case 'i':       Debug_Fmt("%i", args);  break;
389                 case 'u':       Debug_Fmt("%u", args);  break;
390                 case 'x':       Debug_Fmt("0x%x", args);        break;
391                 case 'b':       Debug_Fmt("0b%b", args);        break;
392                 // Extended (64-Bit)
393                 case 'X':       Debug_Fmt("0x%llx", args);      break;
394                 case 'B':       Debug_Fmt("0b%llb", args);      break;
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