|
|
1.1 ! root 1: // Raw screen writing and debug output code. ! 2: // ! 3: // Copyright (C) 2008,2009 Kevin O'Connor <[email protected]> ! 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 "util.h" // printf ! 11: #include "bregs.h" // struct bregs ! 12: #include "config.h" // CONFIG_* ! 13: #include "biosvar.h" // GET_GLOBAL ! 14: ! 15: struct putcinfo { ! 16: void (*func)(struct putcinfo *info, char c); ! 17: }; ! 18: ! 19: ! 20: /**************************************************************** ! 21: * Debug output ! 22: ****************************************************************/ ! 23: ! 24: #define DEBUG_PORT PORT_SERIAL1 ! 25: #define DEBUG_TIMEOUT 100000 ! 26: ! 27: void ! 28: debug_serial_setup() ! 29: { ! 30: if (!CONFIG_DEBUG_SERIAL) ! 31: return; ! 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); ! 36: // Disable irqs ! 37: u8 oldier, newier = 0; ! 38: oldier = inb(DEBUG_PORT+SEROFF_IER); ! 39: outb(newier, DEBUG_PORT+SEROFF_IER); ! 40: ! 41: if (oldparam != newparam || oldier != newier) ! 42: dprintf(1, "Changing serial settings was %x/%x now %x/%x\n" ! 43: , oldparam, oldier, newparam, newier); ! 44: } ! 45: ! 46: // Write a character to the serial port. ! 47: static void ! 48: debug_serial(char c) ! 49: { ! 50: if (!CONFIG_DEBUG_SERIAL) ! 51: return; ! 52: int timeout = DEBUG_TIMEOUT; ! 53: while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x60) != 0x60) ! 54: if (!timeout--) ! 55: // Ran out of time. ! 56: return; ! 57: outb(c, DEBUG_PORT+SEROFF_DATA); ! 58: } ! 59: ! 60: // Make sure all serial port writes have been completely sent. ! 61: static void ! 62: debug_serial_flush() ! 63: { ! 64: if (!CONFIG_DEBUG_SERIAL) ! 65: return; ! 66: int timeout = DEBUG_TIMEOUT; ! 67: while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x40) != 0x40) ! 68: if (!timeout--) ! 69: // Ran out of time. ! 70: return; ! 71: } ! 72: ! 73: // Write a character to debug port(s). ! 74: static void ! 75: putc_debug(struct putcinfo *action, char c) ! 76: { ! 77: if (! CONFIG_DEBUG_LEVEL) ! 78: return; ! 79: if (! CONFIG_COREBOOT) ! 80: // Send character to debug port. ! 81: outb(c, PORT_BIOS_DEBUG); ! 82: if (c == '\n') ! 83: debug_serial('\r'); ! 84: debug_serial(c); ! 85: } ! 86: ! 87: // In 16bit mode just need a dummy variable (putc_debug is always used ! 88: // anyway), and in 32bit mode need a pointer to the 32bit instance of ! 89: // putc_debug(). ! 90: #if MODE16 ! 91: static struct putcinfo debuginfo VAR16; ! 92: #else ! 93: static struct putcinfo debuginfo = { putc_debug }; ! 94: #endif ! 95: ! 96: ! 97: /**************************************************************** ! 98: * Screen writing ! 99: ****************************************************************/ ! 100: ! 101: // Show a character on the screen. ! 102: static void ! 103: screenc(char c) ! 104: { ! 105: struct bregs br; ! 106: memset(&br, 0, sizeof(br)); ! 107: br.flags = F_IF; ! 108: br.ah = 0x0e; ! 109: br.al = c; ! 110: call16_int(0x10, &br); ! 111: } ! 112: ! 113: // Handle a character from a printf request. ! 114: static void ! 115: putc_screen(struct putcinfo *action, char c) ! 116: { ! 117: if (CONFIG_SCREEN_AND_DEBUG) ! 118: putc_debug(&debuginfo, c); ! 119: if (c == '\n') ! 120: screenc('\r'); ! 121: screenc(c); ! 122: } ! 123: ! 124: static struct putcinfo screeninfo = { putc_screen }; ! 125: ! 126: ! 127: /**************************************************************** ! 128: * Xprintf code ! 129: ****************************************************************/ ! 130: ! 131: // Output a character. ! 132: static void ! 133: putc(struct putcinfo *action, char c) ! 134: { ! 135: if (MODE16) { ! 136: // Only debugging output supported in 16bit mode. ! 137: putc_debug(action, c); ! 138: return; ! 139: } ! 140: ! 141: void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func); ! 142: func(action, c); ! 143: } ! 144: ! 145: // Ouptut a string. ! 146: static void ! 147: puts(struct putcinfo *action, const char *s) ! 148: { ! 149: for (; *s; s++) ! 150: putc(action, *s); ! 151: } ! 152: ! 153: // Output a string that is in the CS segment. ! 154: static void ! 155: puts_cs(struct putcinfo *action, const char *s) ! 156: { ! 157: char *vs = (char*)s; ! 158: for (;; vs++) { ! 159: char c = GET_GLOBAL(*vs); ! 160: if (!c) ! 161: break; ! 162: putc(action, c); ! 163: } ! 164: } ! 165: ! 166: // Output an unsigned integer. ! 167: static void ! 168: putuint(struct putcinfo *action, u32 val) ! 169: { ! 170: char buf[12]; ! 171: char *d = &buf[sizeof(buf) - 1]; ! 172: *d-- = '\0'; ! 173: for (;;) { ! 174: *d = (val % 10) + '0'; ! 175: val /= 10; ! 176: if (!val) ! 177: break; ! 178: d--; ! 179: } ! 180: puts(action, d); ! 181: } ! 182: ! 183: // Output a single digit hex character. ! 184: static inline void ! 185: putsinglehex(struct putcinfo *action, u32 val) ! 186: { ! 187: if (val <= 9) ! 188: val = '0' + val; ! 189: else ! 190: val = 'a' + val - 10; ! 191: putc(action, val); ! 192: } ! 193: ! 194: // Output an integer in hexadecimal. ! 195: static void ! 196: puthex(struct putcinfo *action, u32 val, int width) ! 197: { ! 198: if (!width) { ! 199: u32 tmp = val; ! 200: width = 1; ! 201: if (tmp > 0xffff) { ! 202: width += 4; ! 203: tmp >>= 16; ! 204: } ! 205: if (tmp > 0xff) { ! 206: width += 2; ! 207: tmp >>= 8; ! 208: } ! 209: if (tmp > 0xf) ! 210: width += 1; ! 211: } ! 212: ! 213: switch (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); ! 222: } ! 223: } ! 224: ! 225: static inline int ! 226: isdigit(u8 c) ! 227: { ! 228: return ((u8)(c - '0')) < 10; ! 229: } ! 230: ! 231: static void ! 232: bvprintf(struct putcinfo *action, const char *fmt, va_list args) ! 233: { ! 234: const char *s = fmt; ! 235: for (;; s++) { ! 236: char c = GET_GLOBAL(*(u8*)s); ! 237: if (!c) ! 238: break; ! 239: if (c != '%') { ! 240: putc(action, c); ! 241: continue; ! 242: } ! 243: const char *n = s+1; ! 244: int field_width = 0; ! 245: for (;;) { ! 246: c = GET_GLOBAL(*(u8*)n); ! 247: if (!isdigit(c)) ! 248: break; ! 249: field_width = field_width * 10 + c - '0'; ! 250: n++; ! 251: } ! 252: if (c == 'l') { ! 253: // Ignore long format indicator ! 254: n++; ! 255: c = GET_GLOBAL(*(u8*)n); ! 256: } ! 257: s32 val; ! 258: const char *sarg; ! 259: switch (c) { ! 260: case '%': ! 261: putc(action, '%'); ! 262: break; ! 263: case 'd': ! 264: val = va_arg(args, s32); ! 265: if (val < 0) { ! 266: putc(action, '-'); ! 267: val = -val; ! 268: } ! 269: putuint(action, val); ! 270: break; ! 271: case 'u': ! 272: val = va_arg(args, s32); ! 273: putuint(action, val); ! 274: break; ! 275: case 'p': ! 276: /* %p always has 0x prepended */ ! 277: putc(action, '0'); ! 278: putc(action, 'x'); ! 279: field_width = 8; ! 280: case 'x': ! 281: val = va_arg(args, s32); ! 282: puthex(action, val, field_width); ! 283: break; ! 284: case 'c': ! 285: val = va_arg(args, int); ! 286: putc(action, val); ! 287: break; ! 288: case '.': ! 289: // Hack to support "%.s" - meaning string on stack. ! 290: if (GET_GLOBAL(*(u8*)(n+1)) != 's') ! 291: break; ! 292: n++; ! 293: sarg = va_arg(args, const char *); ! 294: puts(action, sarg); ! 295: break; ! 296: case 's': ! 297: sarg = va_arg(args, const char *); ! 298: puts_cs(action, sarg); ! 299: break; ! 300: default: ! 301: putc(action, '%'); ! 302: n = s; ! 303: } ! 304: s = n; ! 305: } ! 306: } ! 307: ! 308: void ! 309: panic(const char *fmt, ...) ! 310: { ! 311: if (CONFIG_DEBUG_LEVEL) { ! 312: va_list args; ! 313: va_start(args, fmt); ! 314: bvprintf(&debuginfo, fmt, args); ! 315: va_end(args); ! 316: debug_serial_flush(); ! 317: } ! 318: ! 319: // XXX - use PANIC PORT. ! 320: irq_disable(); ! 321: for (;;) ! 322: hlt(); ! 323: } ! 324: ! 325: void ! 326: __dprintf(const char *fmt, ...) ! 327: { ! 328: if (!MODE16 && 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, ' '); ! 337: } ! 338: } ! 339: ! 340: va_list args; ! 341: va_start(args, fmt); ! 342: bvprintf(&debuginfo, fmt, args); ! 343: va_end(args); ! 344: debug_serial_flush(); ! 345: } ! 346: ! 347: void ! 348: printf(const char *fmt, ...) ! 349: { ! 350: ASSERT32(); ! 351: va_list args; ! 352: va_start(args, fmt); ! 353: bvprintf(&screeninfo, fmt, args); ! 354: va_end(args); ! 355: if (CONFIG_SCREEN_AND_DEBUG) ! 356: debug_serial_flush(); ! 357: } ! 358: ! 359: ! 360: /**************************************************************** ! 361: * snprintf ! 362: ****************************************************************/ ! 363: ! 364: struct snprintfinfo { ! 365: struct putcinfo info; ! 366: char *str, *end; ! 367: }; ! 368: ! 369: static void ! 370: putc_str(struct putcinfo *info, char c) ! 371: { ! 372: struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info); ! 373: if (sinfo->str >= sinfo->end) ! 374: return; ! 375: *sinfo->str = c; ! 376: sinfo->str++; ! 377: } ! 378: ! 379: // Build a formatted string. Note, this function returns the actual ! 380: // number of bytes used (not including null) even in the overflow ! 381: // case. ! 382: int ! 383: snprintf(char *str, size_t size, const char *fmt, ...) ! 384: { ! 385: ASSERT32(); ! 386: if (!size) ! 387: return 0; ! 388: struct snprintfinfo sinfo = { { putc_str }, str, str + size }; ! 389: va_list args; ! 390: va_start(args, fmt); ! 391: bvprintf(&sinfo.info, fmt, args); ! 392: va_end(args); ! 393: char *end = sinfo.str; ! 394: if (end >= sinfo.end) ! 395: end = sinfo.end - 1; ! 396: *end = '\0'; ! 397: return end - str; ! 398: } ! 399: ! 400: ! 401: /**************************************************************** ! 402: * Misc helpers ! 403: ****************************************************************/ ! 404: ! 405: void ! 406: hexdump(const void *d, int len) ! 407: { ! 408: int count=0; ! 409: while (len > 0) { ! 410: if (count % 8 == 0) { ! 411: putc(&debuginfo, '\n'); ! 412: puthex(&debuginfo, count*4, 8); ! 413: putc(&debuginfo, ':'); ! 414: } else { ! 415: putc(&debuginfo, ' '); ! 416: } ! 417: puthex(&debuginfo, *(u32*)d, 8); ! 418: count++; ! 419: len-=4; ! 420: d+=4; ! 421: } ! 422: putc(&debuginfo, '\n'); ! 423: debug_serial_flush(); ! 424: } ! 425: ! 426: static void ! 427: dump_regs(struct bregs *regs) ! 428: { ! 429: if (!regs) { ! 430: dprintf(1, " NULL\n"); ! 431: return; ! 432: } ! 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); ! 439: } ! 440: ! 441: // Report entry to an Interrupt Service Routine (ISR). ! 442: void ! 443: __debug_isr(const char *fname) ! 444: { ! 445: puts_cs(&debuginfo, fname); ! 446: putc(&debuginfo, '\n'); ! 447: debug_serial_flush(); ! 448: } ! 449: ! 450: // Function called on handler startup. ! 451: void ! 452: __debug_enter(struct bregs *regs, const char *fname) ! 453: { ! 454: dprintf(1, "enter %s:\n", fname); ! 455: dump_regs(regs); ! 456: } ! 457: ! 458: // Send debugging output info. ! 459: void ! 460: __debug_stub(struct bregs *regs, int lineno, const char *fname) ! 461: { ! 462: dprintf(1, "stub %s:%d:\n", fname, lineno); ! 463: dump_regs(regs); ! 464: } ! 465: ! 466: // Report on an invalid parameter. ! 467: void ! 468: __warn_invalid(struct bregs *regs, int lineno, const char *fname) ! 469: { ! 470: if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) { ! 471: dprintf(1, "invalid %s:%d:\n", fname, lineno); ! 472: dump_regs(regs); ! 473: } ! 474: } ! 475: ! 476: // Report on an unimplemented feature. ! 477: void ! 478: __warn_unimplemented(struct bregs *regs, int lineno, const char *fname) ! 479: { ! 480: if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) { ! 481: dprintf(1, "unimplemented %s:%d:\n", fname, lineno); ! 482: dump_regs(regs); ! 483: } ! 484: } ! 485: ! 486: // Report a handler reporting an invalid parameter to the caller. ! 487: void ! 488: __set_invalid(struct bregs *regs, int lineno, const char *fname) ! 489: { ! 490: __warn_invalid(regs, lineno, fname); ! 491: set_invalid_silent(regs); ! 492: } ! 493: ! 494: // Report a call of an unimplemented function. ! 495: void ! 496: __set_unimplemented(struct bregs *regs, int lineno, const char *fname) ! 497: { ! 498: __warn_unimplemented(regs, lineno, fname); ! 499: set_invalid_silent(regs); ! 500: } ! 501: ! 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. ! 506: void ! 507: __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname) ! 508: { ! 509: u8 code = linecode; ! 510: u32 lineno = linecode >> 8; ! 511: __warn_invalid(regs, lineno, fname); ! 512: set_code_invalid_silent(regs, code); ! 513: } ! 514: ! 515: // Report a call of an unimplemented function. ! 516: void ! 517: __set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname) ! 518: { ! 519: u8 code = linecode; ! 520: u32 lineno = linecode >> 8; ! 521: __warn_unimplemented(regs, lineno, fname); ! 522: set_code_invalid_silent(regs, code); ! 523: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.