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