1 // Raw screen writing and debug output code.
3 // Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
7 #include <stdarg.h> // va_list
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
16 void (*func)(struct putcinfo *info, char c);
20 /****************************************************************
22 ****************************************************************/
24 #define DEBUG_TIMEOUT 100000
27 debug_serial_setup(void)
29 if (!CONFIG_DEBUG_SERIAL)
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);
36 u8 oldier, newier = 0;
37 oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
38 outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
40 if (oldparam != newparam || oldier != newier)
41 dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
42 , oldparam, oldier, newparam, newier);
45 // Write a character to the serial port.
49 if (!CONFIG_DEBUG_SERIAL)
51 int timeout = DEBUG_TIMEOUT;
52 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
56 outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
59 // Make sure all serial port writes have been completely sent.
61 debug_serial_flush(void)
63 if (!CONFIG_DEBUG_SERIAL)
65 int timeout = DEBUG_TIMEOUT;
66 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
72 // Write a character to debug port(s).
74 putc_debug(struct putcinfo *action, char c)
76 if (! CONFIG_DEBUG_LEVEL)
78 if (! CONFIG_COREBOOT)
79 // Send character to debug port.
80 outb(c, PORT_BIOS_DEBUG);
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().
90 static struct putcinfo debuginfo VAR16;
92 static struct putcinfo debuginfo VAR32SEG;
94 static struct putcinfo debuginfo = { putc_debug };
98 /****************************************************************
100 ****************************************************************/
102 // Show a character on the screen.
107 memset(&br, 0, sizeof(br));
111 call16_int(0x10, &br);
114 // Handle a character from a printf request.
116 putc_screen(struct putcinfo *action, char c)
119 putc_debug(&debuginfo, c);
125 static struct putcinfo screeninfo = { putc_screen };
128 /****************************************************************
130 ****************************************************************/
132 // Output a character.
134 putc(struct putcinfo *action, char c)
137 // Only debugging output supported in segmented mode.
138 putc_debug(action, c);
142 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
148 puts(struct putcinfo *action, const char *s)
150 if (!MODESEGMENT && !s)
156 // Output a string that is in the CS segment.
158 puts_cs(struct putcinfo *action, const char *s)
162 char c = GET_GLOBAL(*vs);
169 // Output an unsigned integer.
171 putuint(struct putcinfo *action, u32 val)
174 char *d = &buf[sizeof(buf) - 1];
177 *d = (val % 10) + '0';
186 // Output a single digit hex character.
188 putsinglehex(struct putcinfo *action, u32 val)
193 val = 'a' + val - 10;
197 // Output an integer in hexadecimal.
199 puthex(struct putcinfo *action, u32 val, int width, int spacepad)
206 } else if (spacepad) {
212 count = width - count;
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);
234 return ((u8)(c - '0')) < 10;
238 bvprintf(struct putcinfo *action, const char *fmt, va_list args)
242 char c = GET_GLOBAL(*(u8*)s);
253 c = GET_GLOBAL(*(u8*)n);
256 if (!field_width && (c == '0'))
259 field_width = field_width * 10 + c - '0';
263 // Ignore long format indicator
265 c = GET_GLOBAL(*(u8*)n);
274 val = va_arg(args, s32);
279 putuint(action, val);
282 val = va_arg(args, s32);
283 putuint(action, val);
286 /* %p always has 0x prepended */
292 val = va_arg(args, s32);
293 puthex(action, val, field_width, spacepad);
296 val = va_arg(args, int);
300 // Hack to support "%.s" - meaning string on stack.
301 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
304 sarg = va_arg(args, const char *);
308 sarg = va_arg(args, const char *);
309 puts_cs(action, sarg);
320 panic(const char *fmt, ...)
322 if (CONFIG_DEBUG_LEVEL) {
325 bvprintf(&debuginfo, fmt, args);
327 debug_serial_flush();
330 // XXX - use PANIC PORT.
337 __dprintf(const char *fmt, ...)
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, ' ');
353 bvprintf(&debuginfo, fmt, args);
355 debug_serial_flush();
359 printf(const char *fmt, ...)
364 bvprintf(&screeninfo, fmt, args);
367 debug_serial_flush();
371 /****************************************************************
373 ****************************************************************/
375 struct snprintfinfo {
376 struct putcinfo info;
381 putc_str(struct putcinfo *info, char c)
383 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
384 if (sinfo->str >= sinfo->end)
390 // Build a formatted string. Note, this function returns the actual
391 // number of bytes used (not including null) even in the overflow
394 snprintf(char *str, size_t size, const char *fmt, ...)
399 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
402 bvprintf(&sinfo.info, fmt, args);
404 char *end = sinfo.str;
405 if (end >= sinfo.end)
411 // Build a formatted string - malloc'ing the memory.
413 znprintf(size_t size, const char *fmt, ...)
418 char *str = malloc_tmp(size);
423 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
426 bvprintf(&sinfo.info, fmt, args);
428 char *end = sinfo.str;
429 if (end >= sinfo.end)
436 /****************************************************************
438 ****************************************************************/
441 hexdump(const void *d, int len)
445 if (count % 8 == 0) {
446 putc(&debuginfo, '\n');
447 puthex(&debuginfo, count*4, 8, 0);
448 putc(&debuginfo, ':');
450 putc(&debuginfo, ' ');
452 puthex(&debuginfo, *(u32*)d, 8, 0);
457 putc(&debuginfo, '\n');
458 debug_serial_flush();
462 dump_regs(struct bregs *regs)
465 dprintf(1, " NULL\n");
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)®s[1]
473 , regs->code.seg, regs->code.offset, regs->flags);
476 // Report entry to an Interrupt Service Routine (ISR).
478 __debug_isr(const char *fname)
480 puts_cs(&debuginfo, fname);
481 putc(&debuginfo, '\n');
482 debug_serial_flush();
485 // Function called on handler startup.
487 __debug_enter(struct bregs *regs, const char *fname)
489 dprintf(1, "enter %s:\n", fname);
493 // Send debugging output info.
495 __debug_stub(struct bregs *regs, int lineno, const char *fname)
497 dprintf(1, "stub %s:%d:\n", fname, lineno);
501 // Report on an invalid parameter.
503 __warn_invalid(struct bregs *regs, int lineno, const char *fname)
505 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
506 dprintf(1, "invalid %s:%d:\n", fname, lineno);
511 // Report on an unimplemented feature.
513 __warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
515 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
516 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
521 // Report a detected internal inconsistency.
523 __warn_internalerror(int lineno, const char *fname)
525 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
529 // Report on an allocation failure.
531 __warn_noalloc(int lineno, const char *fname)
533 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
537 // Report on a timeout exceeded.
539 __warn_timeout(int lineno, const char *fname)
541 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
544 // Report a handler reporting an invalid parameter to the caller.
546 __set_invalid(struct bregs *regs, int lineno, const char *fname)
548 __warn_invalid(regs, lineno, fname);
549 set_invalid_silent(regs);
552 // Report a call of an unimplemented function.
554 __set_unimplemented(struct bregs *regs, int lineno, const char *fname)
556 __warn_unimplemented(regs, lineno, fname);
557 set_invalid_silent(regs);
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.
565 __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
568 u32 lineno = linecode >> 8;
569 __warn_invalid(regs, lineno, fname);
570 set_code_invalid_silent(regs, code);
573 // Report a call of an unimplemented function.
575 __set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
578 u32 lineno = linecode >> 8;
579 __warn_unimplemented(regs, lineno, fname);
580 set_code_invalid_silent(regs, code);