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