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