X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Foutput.c;h=2e6246b6ad7884659be3a7c80a302a4cd480cb10;hb=f358759fb65939bb79a379b8e9d1e7c379f90d89;hp=760ea417f466c6d486b9b3eaa2669644c11069c3;hpb=ed12849c9b06e371f11596a32da5997c96d9bc95;p=seabios.git diff --git a/src/output.c b/src/output.c index 760ea41..2e6246b 100644 --- a/src/output.c +++ b/src/output.c @@ -1,18 +1,58 @@ -// Raw screen writing code. +// Raw screen writing and debug output code. // // Copyright (C) 2008 Kevin O'Connor // -// This file may be distributed under the terms of the GNU GPLv3 license. +// This file may be distributed under the terms of the GNU LGPLv3 license. #include // va_list #include "farptr.h" // GET_VAR -#include "util.h" // bprintf -#include "biosvar.h" // struct bregs +#include "util.h" // printf +#include "bregs.h" // struct bregs +#include "config.h" // CONFIG_* +#include "biosvar.h" // GET_GLOBAL +#define DEBUG_PORT 0x03f8 +#define DEBUG_TIMEOUT 100000 + +void +debug_serial_setup() +{ + if (!CONFIG_DEBUG_SERIAL) + return; + // setup for serial logging: 8N1 + u8 oldparam, newparam = 0x03; + oldparam = inb(DEBUG_PORT+3); + outb(newparam, DEBUG_PORT+3); + // Disable irqs + u8 oldier, newier = 0; + oldier = inb(DEBUG_PORT+1); + outb(newier, DEBUG_PORT+1); + + if (oldparam != newparam || oldier != newier) + dprintf(1, "Changing serial settings was %x/%x now %x/%x\n" + , oldparam, oldier, newparam, newier); +} + +// Write a character to the serial port. +static void +debug_serial(char c) +{ + int timeout = DEBUG_TIMEOUT; + while ((inb(DEBUG_PORT+5) & 0x60) != 0x60) + if (!timeout--) + // Ran out of time. + return; + outb(c, DEBUG_PORT); +} + +// Show a character on the screen. static void screenc(u8 c) { + if (MODE16) + // printf is only used in 32bit code. + return; struct bregs br; memset(&br, 0, sizeof(br)); br.ah = 0x0e; @@ -20,22 +60,31 @@ screenc(u8 c) call16_int(0x10, &br); } -// XXX -#define PORT_DEBUG 0x403 - -// Write a charcter to the framebuffer. +// Output a character. static void putc(u16 action, char c) { - outb(c, PORT_DEBUG); + if (CONFIG_DEBUG_LEVEL) { + if (! CONFIG_COREBOOT) + // Send character to debug port. + outb(c, PORT_BIOS_DEBUG); + if (CONFIG_DEBUG_SERIAL) { + // Send character to serial port. + if (c == '\n') + debug_serial('\r'); + debug_serial(c); + } + } + if (action) { + // Send character to video screen. if (c == '\n') screenc('\r'); screenc(c); } } -// Write a string to the framebuffer. +// Ouptut a string. static void puts(u16 action, const char *s) { @@ -43,19 +92,19 @@ puts(u16 action, const char *s) putc(action, *s); } -// Write a string to the framebuffer. +// Output a string that is in the CS segment. static void puts_cs(u16 action, const char *s) { for (;; s++) { - char c = GET_VAR(CS, (u8)*s); + char c = GET_GLOBAL(*(u8*)s); if (!c) break; putc(action, c); } } -// Write an unsigned integer to the screen. +// Output an unsigned integer. static void putuint(u16 action, u32 val) { @@ -72,7 +121,7 @@ putuint(u16 action, u32 val) puts(action, d); } -// Write a single digit hex character to the screen. +// Output a single digit hex character. static inline void putsinglehex(u16 action, u32 val) { @@ -83,7 +132,7 @@ putsinglehex(u16 action, u32 val) putc(action, val); } -// Write an integer in hexadecimal to the screen. +// Output an integer in hexadecimal. static void puthex(u16 action, u32 val) { @@ -100,17 +149,15 @@ puthex(u16 action, u32 val) static inline int isdigit(u8 c) { - return c - '0' < 10; + return ((u8)(c - '0')) < 10; } -void -bprintf(u16 action, const char *fmt, ...) +static void +bvprintf(u16 action, const char *fmt, va_list args) { - va_list args; - va_start(args, fmt); const char *s = fmt; for (;; s++) { - char c = GET_VAR(CS, (u8)*s); + char c = GET_GLOBAL(*(u8*)s); if (!c) break; if (c != '%') { @@ -119,7 +166,7 @@ bprintf(u16 action, const char *fmt, ...) } const char *n = s+1; for (;;) { - c = GET_VAR(CS, (u8)*n); + c = GET_GLOBAL(*(u8*)n); if (!isdigit(c)) break; n++; @@ -127,7 +174,7 @@ bprintf(u16 action, const char *fmt, ...) if (c == 'l') { // Ignore long format indicator n++; - c = GET_VAR(CS, (u8)*n); + c = GET_GLOBAL(*(u8*)n); } s32 val; const char *sarg; @@ -147,6 +194,7 @@ bprintf(u16 action, const char *fmt, ...) val = va_arg(args, s32); putuint(action, val); break; + case 'p': case 'x': val = va_arg(args, s32); puthex(action, val); @@ -155,6 +203,14 @@ bprintf(u16 action, const char *fmt, ...) val = va_arg(args, int); putc(action, val); break; + case '.': + // Hack to support "%.s" - meaning string on stack. + if (GET_GLOBAL(*(u8*)(n+1)) != 's') + break; + n++; + sarg = va_arg(args, const char *); + puts(action, sarg); + break; case 's': sarg = va_arg(args, const char *); puts_cs(action, sarg); @@ -165,24 +221,57 @@ bprintf(u16 action, const char *fmt, ...) } s = n; } +} + +void +panic(const char *fmt, ...) +{ + if (CONFIG_DEBUG_LEVEL) { + va_list args; + va_start(args, fmt); + bvprintf(0, fmt, args); + va_end(args); + } + + // XXX - use PANIC PORT. + irq_disable(); + for (;;) + hlt(); +} + +void +__dprintf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + bvprintf(0, fmt, args); + va_end(args); +} + +void +printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + bvprintf(1, fmt, args); va_end(args); } static void -dump_regs(const char *fname, const char *type, struct bregs *regs) +dump_regs(struct bregs *regs) { if (!regs) { - bprintf(0, "%s %s: NULL\n", type, fname); + dprintf(1, " NULL\n"); return; } - bprintf(0, "%s %s: a=%x b=%x c=%x d=%x si=%x di=%x\n" - , type, fname, regs->eax, regs->ebx, regs->ecx, regs->edx + dprintf(1, " a=%x b=%x c=%x d=%x si=%x di=%x\n" + , regs->eax, regs->ebx, regs->ecx, regs->edx , regs->esi, regs->edi); - bprintf(0, " ds=%x es=%x bp=%x sp=%x ip=%x cs=%x f=%x\n" - , regs->ds, regs->es, regs->ebp, regs->esp - , regs->ip, regs->cs, regs->flags); + dprintf(1, " ds=%x es=%x ip=%x cs=%x f=%x r=%p\n" + , regs->ds, regs->es, regs->ip, regs->cs, regs->flags, regs); } +// Report entry to an Interrupt Service Routine (ISR). void __debug_isr(const char *fname) { @@ -192,20 +281,39 @@ __debug_isr(const char *fname) // Function called on handler startup. void -__debug_enter(const char *fname, struct bregs *regs) +__debug_enter(struct bregs *regs, const char *fname) +{ + dprintf(1, "enter %s:\n", fname); + dump_regs(regs); +} + +// Send debugging output info. +void +__debug_stub(struct bregs *regs, int lineno, const char *fname) { - // XXX - implement run time suppression test - dump_regs(fname, "enter", regs); + dprintf(1, "stub %s:%d:\n", fname, lineno); + dump_regs(regs); } +// Report on a handler returning a failure notification to the caller. void -__debug_fail(const char *fname, struct bregs *regs) +__set_fail(struct bregs *regs, int lineno, const char *fname) { - dump_regs(fname, "fail", regs); + dprintf(1, "fail %s:%d:\n", fname, lineno); + dump_regs(regs); + set_fail_silent(regs); } +// Report on a handler returning a failure code to the caller. Note, +// the lineno and return code are encoded in the same parameter as gcc +// does a better job of scheduling function calls when there are 3 or +// less parameters. void -__debug_stub(const char *fname, struct bregs *regs) +__set_code_fail(struct bregs *regs, u32 linecode, const char *fname) { - dump_regs(fname, "stub", regs); + u8 code = linecode; + u32 lineno = linecode >> 8; + dprintf(1, "fail %s:%d(%x):\n", fname, lineno, code); + dump_regs(regs); + set_code_fail_silent(regs, code); }