Tizen 2.1 base
[sdk/emulator/qemu.git] / roms / seabios / src / output.c
1 // Raw screen writing and debug output code.
2 //
3 // Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include <stdarg.h> // va_list
8
9 #include "farptr.h" // GET_VAR
10 #include "util.h" // printf
11 #include "bregs.h" // struct bregs
12 #include "config.h" // CONFIG_*
13 #include "biosvar.h" // GET_GLOBAL
14
15 struct putcinfo {
16     void (*func)(struct putcinfo *info, char c);
17 };
18
19
20 /****************************************************************
21  * Debug output
22  ****************************************************************/
23
24 #define DEBUG_PORT PORT_SERIAL1
25 #define DEBUG_TIMEOUT 100000
26
27 void
28 debug_serial_setup(void)
29 {
30     if (!CONFIG_DEBUG_SERIAL)
31         return;
32     // setup for serial logging: 8N1
33     u8 oldparam, newparam = 0x03;
34     oldparam = inb(DEBUG_PORT+SEROFF_LCR);
35     outb(newparam, DEBUG_PORT+SEROFF_LCR);
36     // Disable irqs
37     u8 oldier, newier = 0;
38     oldier = inb(DEBUG_PORT+SEROFF_IER);
39     outb(newier, DEBUG_PORT+SEROFF_IER);
40
41     if (oldparam != newparam || oldier != newier)
42         dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
43                 , oldparam, oldier, newparam, newier);
44 }
45
46 // Write a character to the serial port.
47 static void
48 debug_serial(char c)
49 {
50     if (!CONFIG_DEBUG_SERIAL)
51         return;
52     int timeout = DEBUG_TIMEOUT;
53     while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x60) != 0x60)
54         if (!timeout--)
55             // Ran out of time.
56             return;
57     outb(c, DEBUG_PORT+SEROFF_DATA);
58 }
59
60 // Make sure all serial port writes have been completely sent.
61 static void
62 debug_serial_flush(void)
63 {
64     if (!CONFIG_DEBUG_SERIAL)
65         return;
66     int timeout = DEBUG_TIMEOUT;
67     while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x40) != 0x40)
68         if (!timeout--)
69             // Ran out of time.
70             return;
71 }
72
73 // Write a character to debug port(s).
74 static void
75 putc_debug(struct putcinfo *action, char c)
76 {
77     if (! CONFIG_DEBUG_LEVEL)
78         return;
79     if (! CONFIG_COREBOOT)
80         // Send character to debug port.
81         outb(c, PORT_BIOS_DEBUG);
82     if (c == '\n')
83         debug_serial('\r');
84     debug_serial(c);
85 }
86
87 // In segmented mode just need a dummy variable (putc_debug is always
88 // used anyway), and in 32bit flat mode need a pointer to the 32bit
89 // instance of putc_debug().
90 #if MODE16
91 static struct putcinfo debuginfo VAR16;
92 #elif MODESEGMENT
93 static struct putcinfo debuginfo VAR32SEG;
94 #else
95 static struct putcinfo debuginfo = { putc_debug };
96 #endif
97
98
99 /****************************************************************
100  * Screen writing
101  ****************************************************************/
102
103 // Show a character on the screen.
104 static void
105 screenc(char c)
106 {
107     struct bregs br;
108     memset(&br, 0, sizeof(br));
109     br.flags = F_IF;
110     br.ah = 0x0e;
111     br.al = c;
112     call16_int(0x10, &br);
113 }
114
115 // Handle a character from a printf request.
116 static void
117 putc_screen(struct putcinfo *action, char c)
118 {
119     if (CONFIG_SCREEN_AND_DEBUG)
120         putc_debug(&debuginfo, c);
121     if (c == '\n')
122         screenc('\r');
123     screenc(c);
124 }
125
126 static struct putcinfo screeninfo = { putc_screen };
127
128
129 /****************************************************************
130  * Xprintf code
131  ****************************************************************/
132
133 // Output a character.
134 static void
135 putc(struct putcinfo *action, char c)
136 {
137     if (MODESEGMENT) {
138         // Only debugging output supported in segmented mode.
139         putc_debug(action, c);
140         return;
141     }
142
143     void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
144     func(action, c);
145 }
146
147 // Ouptut a string.
148 static void
149 puts(struct putcinfo *action, const char *s)
150 {
151     for (; *s; s++)
152         putc(action, *s);
153 }
154
155 // Output a string that is in the CS segment.
156 static void
157 puts_cs(struct putcinfo *action, const char *s)
158 {
159     char *vs = (char*)s;
160     for (;; vs++) {
161         char c = GET_GLOBAL(*vs);
162         if (!c)
163             break;
164         putc(action, c);
165     }
166 }
167
168 // Output an unsigned integer.
169 static void
170 putuint(struct putcinfo *action, u32 val)
171 {
172     char buf[12];
173     char *d = &buf[sizeof(buf) - 1];
174     *d-- = '\0';
175     for (;;) {
176         *d = (val % 10) + '0';
177         val /= 10;
178         if (!val)
179             break;
180         d--;
181     }
182     puts(action, d);
183 }
184
185 // Output a single digit hex character.
186 static inline void
187 putsinglehex(struct putcinfo *action, u32 val)
188 {
189     if (val <= 9)
190         val = '0' + val;
191     else
192         val = 'a' + val - 10;
193     putc(action, val);
194 }
195
196 // Output an integer in hexadecimal.
197 static void
198 puthex(struct putcinfo *action, u32 val, int width, int spacepad)
199 {
200     if (!width) {
201         u32 tmp = val;
202         width = 1;
203         while (tmp >>= 4)
204             width++;
205     } else if (spacepad)  {
206         u32 tmp = val;
207         u32 count = 1;
208         while (tmp >>= 4)
209             count++;
210         if (width > count) {
211             count = width - count;
212             width -= count;
213             while (count--)
214                 putc(action, ' ');
215         }
216     }
217
218     switch (width) {
219     default: putsinglehex(action, (val >> 28) & 0xf);
220     case 7:  putsinglehex(action, (val >> 24) & 0xf);
221     case 6:  putsinglehex(action, (val >> 20) & 0xf);
222     case 5:  putsinglehex(action, (val >> 16) & 0xf);
223     case 4:  putsinglehex(action, (val >> 12) & 0xf);
224     case 3:  putsinglehex(action, (val >> 8) & 0xf);
225     case 2:  putsinglehex(action, (val >> 4) & 0xf);
226     case 1:  putsinglehex(action, (val >> 0) & 0xf);
227     }
228 }
229
230 static inline int
231 isdigit(u8 c)
232 {
233     return ((u8)(c - '0')) < 10;
234 }
235
236 static void
237 bvprintf(struct putcinfo *action, const char *fmt, va_list args)
238 {
239     const char *s = fmt;
240     for (;; s++) {
241         char c = GET_GLOBAL(*(u8*)s);
242         if (!c)
243             break;
244         if (c != '%') {
245             putc(action, c);
246             continue;
247         }
248         const char *n = s+1;
249         int field_width = 0;
250         int spacepad = 1;
251         for (;;) {
252             c = GET_GLOBAL(*(u8*)n);
253             if (!isdigit(c))
254                 break;
255             if (!field_width && (c == '0'))
256                 spacepad = 0;
257             else
258                 field_width = field_width * 10 + c - '0';
259             n++;
260         }
261         if (c == 'l') {
262             // Ignore long format indicator
263             n++;
264             c = GET_GLOBAL(*(u8*)n);
265         }
266         s32 val;
267         const char *sarg;
268         switch (c) {
269         case '%':
270             putc(action, '%');
271             break;
272         case 'd':
273             val = va_arg(args, s32);
274             if (val < 0) {
275                 putc(action, '-');
276                 val = -val;
277             }
278             putuint(action, val);
279             break;
280         case 'u':
281             val = va_arg(args, s32);
282             putuint(action, val);
283             break;
284         case 'p':
285             /* %p always has 0x prepended */
286             putc(action, '0');
287             putc(action, 'x');
288             field_width = 8;
289             spacepad = 0;
290         case 'x':
291             val = va_arg(args, s32);
292             puthex(action, val, field_width, spacepad);
293             break;
294         case 'c':
295             val = va_arg(args, int);
296             putc(action, val);
297             break;
298         case '.':
299             // Hack to support "%.s" - meaning string on stack.
300             if (GET_GLOBAL(*(u8*)(n+1)) != 's')
301                 break;
302             n++;
303             sarg = va_arg(args, const char *);
304             puts(action, sarg);
305             break;
306         case 's':
307             sarg = va_arg(args, const char *);
308             puts_cs(action, sarg);
309             break;
310         default:
311             putc(action, '%');
312             n = s;
313         }
314         s = n;
315     }
316 }
317
318 void
319 panic(const char *fmt, ...)
320 {
321     if (CONFIG_DEBUG_LEVEL) {
322         va_list args;
323         va_start(args, fmt);
324         bvprintf(&debuginfo, fmt, args);
325         va_end(args);
326         debug_serial_flush();
327     }
328
329     // XXX - use PANIC PORT.
330     irq_disable();
331     for (;;)
332         hlt();
333 }
334
335 void
336 __dprintf(const char *fmt, ...)
337 {
338     if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
339         && *fmt != '\\' && *fmt != '/') {
340         struct thread_info *cur = getCurThread();
341         if (cur != &MainThread) {
342             // Show "thread id" for this debug message.
343             putc_debug(&debuginfo, '|');
344             puthex(&debuginfo, (u32)cur, 8, 0);
345             putc_debug(&debuginfo, '|');
346             putc_debug(&debuginfo, ' ');
347         }
348     }
349
350     va_list args;
351     va_start(args, fmt);
352     bvprintf(&debuginfo, fmt, args);
353     va_end(args);
354     debug_serial_flush();
355 }
356
357 void
358 printf(const char *fmt, ...)
359 {
360     ASSERT32FLAT();
361     va_list args;
362     va_start(args, fmt);
363     bvprintf(&screeninfo, fmt, args);
364     va_end(args);
365     if (CONFIG_SCREEN_AND_DEBUG)
366         debug_serial_flush();
367 }
368
369
370 /****************************************************************
371  * snprintf
372  ****************************************************************/
373
374 struct snprintfinfo {
375     struct putcinfo info;
376     char *str, *end;
377 };
378
379 static void
380 putc_str(struct putcinfo *info, char c)
381 {
382     struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
383     if (sinfo->str >= sinfo->end)
384         return;
385     *sinfo->str = c;
386     sinfo->str++;
387 }
388
389 // Build a formatted string.  Note, this function returns the actual
390 // number of bytes used (not including null) even in the overflow
391 // case.
392 int
393 snprintf(char *str, size_t size, const char *fmt, ...)
394 {
395     ASSERT32FLAT();
396     if (!size)
397         return 0;
398     struct snprintfinfo sinfo = { { putc_str }, str, str + size };
399     va_list args;
400     va_start(args, fmt);
401     bvprintf(&sinfo.info, fmt, args);
402     va_end(args);
403     char *end = sinfo.str;
404     if (end >= sinfo.end)
405         end = sinfo.end - 1;
406     *end = '\0';
407     return end - str;
408 }
409
410
411 /****************************************************************
412  * Misc helpers
413  ****************************************************************/
414
415 void
416 hexdump(const void *d, int len)
417 {
418     int count=0;
419     while (len > 0) {
420         if (count % 8 == 0) {
421             putc(&debuginfo, '\n');
422             puthex(&debuginfo, count*4, 8, 0);
423             putc(&debuginfo, ':');
424         } else {
425             putc(&debuginfo, ' ');
426         }
427         puthex(&debuginfo, *(u32*)d, 8, 0);
428         count++;
429         len-=4;
430         d+=4;
431     }
432     putc(&debuginfo, '\n');
433     debug_serial_flush();
434 }
435
436 static void
437 dump_regs(struct bregs *regs)
438 {
439     if (!regs) {
440         dprintf(1, "  NULL\n");
441         return;
442     }
443     dprintf(1, "   a=%08x  b=%08x  c=%08x  d=%08x ds=%04x es=%04x ss=%04x\n"
444             , regs->eax, regs->ebx, regs->ecx, regs->edx
445             , regs->ds, regs->es, GET_SEG(SS));
446     dprintf(1, "  si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x  f=%04x\n"
447             , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
448             , regs->code.seg, regs->code.offset, regs->flags);
449 }
450
451 // Report entry to an Interrupt Service Routine (ISR).
452 void
453 __debug_isr(const char *fname)
454 {
455     puts_cs(&debuginfo, fname);
456     putc(&debuginfo, '\n');
457     debug_serial_flush();
458 }
459
460 // Function called on handler startup.
461 void
462 __debug_enter(struct bregs *regs, const char *fname)
463 {
464     dprintf(1, "enter %s:\n", fname);
465     dump_regs(regs);
466 }
467
468 // Send debugging output info.
469 void
470 __debug_stub(struct bregs *regs, int lineno, const char *fname)
471 {
472     dprintf(1, "stub %s:%d:\n", fname, lineno);
473     dump_regs(regs);
474 }
475
476 // Report on an invalid parameter.
477 void
478 __warn_invalid(struct bregs *regs, int lineno, const char *fname)
479 {
480     if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
481         dprintf(1, "invalid %s:%d:\n", fname, lineno);
482         dump_regs(regs);
483     }
484 }
485
486 // Report on an unimplemented feature.
487 void
488 __warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
489 {
490     if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
491         dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
492         dump_regs(regs);
493     }
494 }
495
496 // Report a detected internal inconsistency.
497 void
498 __warn_internalerror(int lineno, const char *fname)
499 {
500     dprintf(1, "WARNING - internal error detected at %s:%d!\n"
501             , fname, lineno);
502 }
503
504 // Report on an allocation failure.
505 void
506 __warn_noalloc(int lineno, const char *fname)
507 {
508     dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
509             , fname, lineno);
510 }
511
512 // Report on a timeout exceeded.
513 void
514 __warn_timeout(int lineno, const char *fname)
515 {
516     dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
517 }
518
519 // Report a handler reporting an invalid parameter to the caller.
520 void
521 __set_invalid(struct bregs *regs, int lineno, const char *fname)
522 {
523     __warn_invalid(regs, lineno, fname);
524     set_invalid_silent(regs);
525 }
526
527 // Report a call of an unimplemented function.
528 void
529 __set_unimplemented(struct bregs *regs, int lineno, const char *fname)
530 {
531     __warn_unimplemented(regs, lineno, fname);
532     set_invalid_silent(regs);
533 }
534
535 // Report a handler reporting an invalid parameter code to the
536 // caller.  Note, the lineno and return code are encoded in the same
537 // parameter as gcc does a better job of scheduling function calls
538 // when there are 3 or less parameters.
539 void
540 __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
541 {
542     u8 code = linecode;
543     u32 lineno = linecode >> 8;
544     __warn_invalid(regs, lineno, fname);
545     set_code_invalid_silent(regs, code);
546 }
547
548 // Report a call of an unimplemented function.
549 void
550 __set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
551 {
552     u8 code = linecode;
553     u32 lineno = linecode >> 8;
554     __warn_unimplemented(regs, lineno, fname);
555     set_code_invalid_silent(regs, code);
556 }