From: Kevin O'Connor Date: Thu, 8 Oct 2009 01:41:08 +0000 (-0400) Subject: Add snprintf support. X-Git-Tag: rel-0.5.0~91 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=9ed6b62c32a42060c9732562d72d17a643ac2b69;p=seabios.git Add snprintf support. Extend bvprintf() code to support building a string. Don't flush the serial port from printf if CONFIG_SCREEN_AND_DEBUG not set. --- diff --git a/src/coreboot.c b/src/coreboot.c index 1b93f48..8ba3fe7 100644 --- a/src/coreboot.c +++ b/src/coreboot.c @@ -526,23 +526,6 @@ cbfs_copyfile(struct cbfs_file *file, void *dst, u32 maxlen) return size; } -static char -getHex(u8 x) -{ - if (x <= 9) - return '0' + x; - return 'a' + x - 10; -} - -static u32 -hexify4(u16 x) -{ - return ((getHex(x&0xf) << 24) - | (getHex((x>>4)&0xf) << 16) - | (getHex((x>>8)&0xf) << 8) - | (getHex(x>>12))); -} - // Find and copy the optionrom for the given vendor/device id. int cbfs_copy_optionrom(void *dst, u32 maxlen, u32 vendev) @@ -551,14 +534,8 @@ cbfs_copy_optionrom(void *dst, u32 maxlen, u32 vendev) return -1; char fname[17]; - // Ughh - poor man's sprintf of "pci%04x,%04x.rom" - *(u32*)fname = 0x20696370; // "pci " - *(u32*)&fname[3] = hexify4(vendev); - fname[7] = ','; - *(u32*)&fname[8] = hexify4(vendev >> 16); - *(u32*)&fname[12] = 0x6d6f722e; // ".rom" - fname[16] = '\0'; - + snprintf(fname, sizeof(fname), "pci%04x,%04x.rom" + , (u16)vendev, vendev >> 16); return cbfs_copyfile(cbfs_finddatafile(fname), dst, maxlen); } diff --git a/src/output.c b/src/output.c index 1637ffd..32d1020 100644 --- a/src/output.c +++ b/src/output.c @@ -12,6 +12,15 @@ #include "config.h" // CONFIG_* #include "biosvar.h" // GET_GLOBAL +struct putcinfo { + void (*func)(struct putcinfo *info, char c); +}; + + +/**************************************************************** + * Debug output + ****************************************************************/ + #define DEBUG_PORT PORT_SERIAL1 #define DEBUG_TIMEOUT 100000 @@ -61,13 +70,31 @@ debug_serial_flush() return; } -// Show a character on the screen. +// Write a character to debug port(s). static void -screenc(u8 c) +putc_debug(struct putcinfo *action, char c) { - if (MODE16) - // printf is only used in 32bit code. + if (! CONFIG_DEBUG_LEVEL) return; + if (! CONFIG_COREBOOT) + // Send character to debug port. + outb(c, PORT_BIOS_DEBUG); + if (c == '\n') + debug_serial('\r'); + debug_serial(c); +} + +static struct putcinfo debuginfo = { putc_debug }; + + +/**************************************************************** + * Screen writing + ****************************************************************/ + +// Show a character on the screen. +static void +screenc(char c) +{ struct bregs br; memset(&br, 0, sizeof(br)); br.flags = F_IF; @@ -76,31 +103,41 @@ screenc(u8 c) call16_int(0x10, &br); } +// Handle a character from a printf request. +static void +putc_screen(struct putcinfo *action, char c) +{ + if (CONFIG_SCREEN_AND_DEBUG) + putc_debug(action, c); + if (c == '\n') + screenc('\r'); + screenc(c); +} + +static struct putcinfo screeninfo = { putc_screen }; + + +/**************************************************************** + * Xprintf code + ****************************************************************/ + // Output a character. static void -putc(u16 action, char c) +putc(struct putcinfo *action, char c) { - if (CONFIG_DEBUG_LEVEL && (CONFIG_SCREEN_AND_DEBUG || !action)) { - if (! CONFIG_COREBOOT) - // Send character to debug port. - outb(c, PORT_BIOS_DEBUG); - // Send character to serial port. - if (c == '\n') - debug_serial('\r'); - debug_serial(c); + if (MODE16) { + // Only debugging output supported in 16bit mode. + putc_debug(action, c); + return; } - if (action) { - // Send character to video screen. - if (c == '\n') - screenc('\r'); - screenc(c); - } + void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func); + func(action, c); } // Ouptut a string. static void -puts(u16 action, const char *s) +puts(struct putcinfo *action, const char *s) { for (; *s; s++) putc(action, *s); @@ -108,7 +145,7 @@ puts(u16 action, const char *s) // Output a string that is in the CS segment. static void -puts_cs(u16 action, const char *s) +puts_cs(struct putcinfo *action, const char *s) { char *vs = (char*)s; for (;; vs++) { @@ -121,7 +158,7 @@ puts_cs(u16 action, const char *s) // Output an unsigned integer. static void -putuint(u16 action, u32 val) +putuint(struct putcinfo *action, u32 val) { char buf[12]; char *d = &buf[sizeof(buf) - 1]; @@ -138,7 +175,7 @@ putuint(u16 action, u32 val) // Output a single digit hex character. static inline void -putsinglehex(u16 action, u32 val) +putsinglehex(struct putcinfo *action, u32 val) { if (val <= 9) val = '0' + val; @@ -149,7 +186,7 @@ putsinglehex(u16 action, u32 val) // Output an integer in hexadecimal. static void -puthex(u16 action, u32 val, int width) +puthex(struct putcinfo *action, u32 val, int width) { if (!width) { u32 tmp = val; @@ -185,7 +222,7 @@ isdigit(u8 c) } static void -bvprintf(u16 action, const char *fmt, va_list args) +bvprintf(struct putcinfo *action, const char *fmt, va_list args) { const char *s = fmt; for (;; s++) { @@ -259,7 +296,6 @@ bvprintf(u16 action, const char *fmt, va_list args) } s = n; } - debug_serial_flush(); } void @@ -268,8 +304,9 @@ panic(const char *fmt, ...) if (CONFIG_DEBUG_LEVEL) { va_list args; va_start(args, fmt); - bvprintf(0, fmt, args); + bvprintf(&debuginfo, fmt, args); va_end(args); + debug_serial_flush(); } // XXX - use PANIC PORT. @@ -283,37 +320,83 @@ __dprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); - bvprintf(0, fmt, args); + bvprintf(&debuginfo, fmt, args); va_end(args); + debug_serial_flush(); } void printf(const char *fmt, ...) { + ASSERT32(); + va_list args; + va_start(args, fmt); + bvprintf(&screeninfo, fmt, args); + va_end(args); + if (CONFIG_SCREEN_AND_DEBUG) + debug_serial_flush(); +} + + +/**************************************************************** + * snprintf + ****************************************************************/ + +struct snprintfinfo { + struct putcinfo info; + char *str, *end; +}; + +static void +putc_str(struct putcinfo *info, char c) +{ + struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info); + if (sinfo->str >= sinfo->end) + return; + *sinfo->str = c; + sinfo->str++; +} + +void +snprintf(char *str, size_t size, const char *fmt, ...) +{ + ASSERT32(); + if (!size) + return; + struct snprintfinfo sinfo = { { putc_str }, str, str + size }; va_list args; va_start(args, fmt); - bvprintf(1, fmt, args); + bvprintf(&sinfo.info, fmt, args); va_end(args); + char *end = sinfo.str; + if (end >= sinfo.end) + end--; + *end = '\0'; } + +/**************************************************************** + * Misc helpers + ****************************************************************/ + void hexdump(const void *d, int len) { int count=0; while (len > 0) { if (count % 8 == 0) { - putc(0, '\n'); - puthex(0, count*4, 8); - putc(0, ':'); + putc(&debuginfo, '\n'); + puthex(&debuginfo, count*4, 8); + putc(&debuginfo, ':'); } else { - putc(0, ' '); + putc(&debuginfo, ' '); } - puthex(0, *(u32*)d, 8); + puthex(&debuginfo, *(u32*)d, 8); count++; len-=4; d+=4; } - putc(0, '\n'); + putc(&debuginfo, '\n'); debug_serial_flush(); } @@ -336,8 +419,8 @@ dump_regs(struct bregs *regs) void __debug_isr(const char *fname) { - puts_cs(0, fname); - putc(0, '\n'); + puts_cs(&debuginfo, fname); + putc(&debuginfo, '\n'); debug_serial_flush(); } diff --git a/src/util.h b/src/util.h index fbcfb79..dd8619b 100644 --- a/src/util.h +++ b/src/util.h @@ -156,6 +156,8 @@ void printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); void __dprintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +void snprintf(char *str, size_t size, const char *fmt, ...) + __attribute__ ((format (printf, 3, 4))); #define dprintf(lvl, fmt, args...) do { \ if (CONFIG_DEBUG_LEVEL && (lvl) <= CONFIG_DEBUG_LEVEL) \ __dprintf((fmt) , ##args ); \ @@ -281,12 +283,15 @@ static inline void *malloc_fseg(u32 size) { static inline void *malloc_tmphigh(u32 size) { return zone_malloc(&ZoneTmpHigh, size, MALLOC_MIN_ALIGN); } -static inline void *memalign_tmphigh(u32 align, u32 size) { - return zone_malloc(&ZoneTmpHigh, size, align); +static inline void *memalign_low(u32 align, u32 size) { + return zone_malloc_low(size, align); } static inline void *memalign_high(u32 align, u32 size) { return zone_malloc(&ZoneHigh, size, align); } +static inline void *memalign_tmphigh(u32 align, u32 size) { + return zone_malloc(&ZoneTmpHigh, size, align); +} // mtrr.c void mtrr_setup(void);