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