Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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