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

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