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_PORT PORT_SERIAL1
25 #define DEBUG_TIMEOUT 100000
30 if (!CONFIG_DEBUG_SERIAL)
32 // setup for serial logging: 8N1
33 u8 oldparam, newparam = 0x03;
34 oldparam = inb(DEBUG_PORT+SEROFF_LCR);
35 outb(newparam, DEBUG_PORT+SEROFF_LCR);
37 u8 oldier, newier = 0;
38 oldier = inb(DEBUG_PORT+SEROFF_IER);
39 outb(newier, DEBUG_PORT+SEROFF_IER);
41 if (oldparam != newparam || oldier != newier)
42 dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
43 , oldparam, oldier, newparam, newier);
46 // Write a character to the serial port.
50 if (!CONFIG_DEBUG_SERIAL)
52 int timeout = DEBUG_TIMEOUT;
53 while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x60) != 0x60)
57 outb(c, DEBUG_PORT+SEROFF_DATA);
60 // Make sure all serial port writes have been completely sent.
64 if (!CONFIG_DEBUG_SERIAL)
66 int timeout = DEBUG_TIMEOUT;
67 while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x40) != 0x40)
73 // Write a character to debug port(s).
75 putc_debug(struct putcinfo *action, char c)
77 if (! CONFIG_DEBUG_LEVEL)
79 if (! CONFIG_COREBOOT)
80 // Send character to debug port.
81 outb(c, PORT_BIOS_DEBUG);
87 // In segmented mode just need a dummy variable (putc_debug is always
88 // used anyway), and in 32bit flat mode need a pointer to the 32bit
89 // instance of putc_debug().
91 static struct putcinfo debuginfo VAR16;
93 static struct putcinfo debuginfo = { putc_debug };
97 /****************************************************************
99 ****************************************************************/
101 // Show a character on the screen.
106 memset(&br, 0, sizeof(br));
110 call16_int(0x10, &br);
113 // Handle a character from a printf request.
115 putc_screen(struct putcinfo *action, char c)
117 if (CONFIG_SCREEN_AND_DEBUG)
118 putc_debug(&debuginfo, c);
124 static struct putcinfo screeninfo = { putc_screen };
127 /****************************************************************
129 ****************************************************************/
131 // Output a character.
133 putc(struct putcinfo *action, char c)
136 // Only debugging output supported in segmented mode.
137 putc_debug(action, c);
141 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
147 puts(struct putcinfo *action, const char *s)
153 // Output a string that is in the CS segment.
155 puts_cs(struct putcinfo *action, const char *s)
159 char c = GET_GLOBAL(*vs);
166 // Output an unsigned integer.
168 putuint(struct putcinfo *action, u32 val)
171 char *d = &buf[sizeof(buf) - 1];
174 *d = (val % 10) + '0';
183 // Output a single digit hex character.
185 putsinglehex(struct putcinfo *action, u32 val)
190 val = 'a' + val - 10;
194 // Output an integer in hexadecimal.
196 puthex(struct putcinfo *action, u32 val, int width)
214 default: putsinglehex(action, (val >> 28) & 0xf);
215 case 7: putsinglehex(action, (val >> 24) & 0xf);
216 case 6: putsinglehex(action, (val >> 20) & 0xf);
217 case 5: putsinglehex(action, (val >> 16) & 0xf);
218 case 4: putsinglehex(action, (val >> 12) & 0xf);
219 case 3: putsinglehex(action, (val >> 8) & 0xf);
220 case 2: putsinglehex(action, (val >> 4) & 0xf);
221 case 1: putsinglehex(action, (val >> 0) & 0xf);
228 return ((u8)(c - '0')) < 10;
232 bvprintf(struct putcinfo *action, const char *fmt, va_list args)
236 char c = GET_GLOBAL(*(u8*)s);
246 c = GET_GLOBAL(*(u8*)n);
249 field_width = field_width * 10 + c - '0';
253 // Ignore long format indicator
255 c = GET_GLOBAL(*(u8*)n);
264 val = va_arg(args, s32);
269 putuint(action, val);
272 val = va_arg(args, s32);
273 putuint(action, val);
276 /* %p always has 0x prepended */
281 val = va_arg(args, s32);
282 puthex(action, val, field_width);
285 val = va_arg(args, int);
289 // Hack to support "%.s" - meaning string on stack.
290 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
293 sarg = va_arg(args, const char *);
297 sarg = va_arg(args, const char *);
298 puts_cs(action, sarg);
309 panic(const char *fmt, ...)
311 if (CONFIG_DEBUG_LEVEL) {
314 bvprintf(&debuginfo, fmt, args);
316 debug_serial_flush();
319 // XXX - use PANIC PORT.
326 __dprintf(const char *fmt, ...)
328 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
329 && *fmt != '\\' && *fmt != '/') {
330 struct thread_info *cur = getCurThread();
331 if (cur != &MainThread) {
332 // Show "thread id" for this debug message.
333 putc_debug(&debuginfo, '|');
334 puthex(&debuginfo, (u32)cur, 8);
335 putc_debug(&debuginfo, '|');
336 putc_debug(&debuginfo, ' ');
342 bvprintf(&debuginfo, fmt, args);
344 debug_serial_flush();
348 printf(const char *fmt, ...)
353 bvprintf(&screeninfo, fmt, args);
355 if (CONFIG_SCREEN_AND_DEBUG)
356 debug_serial_flush();
360 /****************************************************************
362 ****************************************************************/
364 struct snprintfinfo {
365 struct putcinfo info;
370 putc_str(struct putcinfo *info, char c)
372 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
373 if (sinfo->str >= sinfo->end)
379 // Build a formatted string. Note, this function returns the actual
380 // number of bytes used (not including null) even in the overflow
383 snprintf(char *str, size_t size, const char *fmt, ...)
388 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
391 bvprintf(&sinfo.info, fmt, args);
393 char *end = sinfo.str;
394 if (end >= sinfo.end)
401 /****************************************************************
403 ****************************************************************/
406 hexdump(const void *d, int len)
410 if (count % 8 == 0) {
411 putc(&debuginfo, '\n');
412 puthex(&debuginfo, count*4, 8);
413 putc(&debuginfo, ':');
415 putc(&debuginfo, ' ');
417 puthex(&debuginfo, *(u32*)d, 8);
422 putc(&debuginfo, '\n');
423 debug_serial_flush();
427 dump_regs(struct bregs *regs)
430 dprintf(1, " NULL\n");
433 dprintf(1, " a=%08x b=%08x c=%08x d=%08x ds=%04x es=%04x ss=%04x\n"
434 , regs->eax, regs->ebx, regs->ecx, regs->edx
435 , regs->ds, regs->es, GET_SEG(SS));
436 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
437 , regs->esi, regs->edi, regs->ebp, (u32)®s[1]
438 , regs->code.seg, regs->code.offset, regs->flags);
441 // Report entry to an Interrupt Service Routine (ISR).
443 __debug_isr(const char *fname)
445 puts_cs(&debuginfo, fname);
446 putc(&debuginfo, '\n');
447 debug_serial_flush();
450 // Function called on handler startup.
452 __debug_enter(struct bregs *regs, const char *fname)
454 dprintf(1, "enter %s:\n", fname);
458 // Send debugging output info.
460 __debug_stub(struct bregs *regs, int lineno, const char *fname)
462 dprintf(1, "stub %s:%d:\n", fname, lineno);
466 // Report on an invalid parameter.
468 __warn_invalid(struct bregs *regs, int lineno, const char *fname)
470 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
471 dprintf(1, "invalid %s:%d:\n", fname, lineno);
476 // Report on an unimplemented feature.
478 __warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
480 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
481 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
486 // Report a handler reporting an invalid parameter to the caller.
488 __set_invalid(struct bregs *regs, int lineno, const char *fname)
490 __warn_invalid(regs, lineno, fname);
491 set_invalid_silent(regs);
494 // Report a call of an unimplemented function.
496 __set_unimplemented(struct bregs *regs, int lineno, const char *fname)
498 __warn_unimplemented(regs, lineno, fname);
499 set_invalid_silent(regs);
502 // Report a handler reporting an invalid parameter code to the
503 // caller. Note, the lineno and return code are encoded in the same
504 // parameter as gcc does a better job of scheduling function calls
505 // when there are 3 or less parameters.
507 __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
510 u32 lineno = linecode >> 8;
511 __warn_invalid(regs, lineno, fname);
512 set_code_invalid_silent(regs, code);
515 // Report a call of an unimplemented function.
517 __set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
520 u32 lineno = linecode >> 8;
521 __warn_unimplemented(regs, lineno, fname);
522 set_code_invalid_silent(regs, code);