Annotation of qemu/roms/seabios/src/output.c, revision 1.1.1.2

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
1.1.1.2 ! root       28: debug_serial_setup(void)
1.1       root       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
1.1.1.2 ! root       62: debug_serial_flush(void)
1.1       root       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: 
1.1.1.2 ! root       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().
1.1       root       90: #if MODE16
                     91: static struct putcinfo debuginfo VAR16;
1.1.1.2 ! root       92: #elif MODESEGMENT
        !            93: static struct putcinfo debuginfo VAR32SEG;
1.1       root       94: #else
                     95: static struct putcinfo debuginfo = { putc_debug };
                     96: #endif
                     97: 
                     98: 
                     99: /****************************************************************
                    100:  * Screen writing
                    101:  ****************************************************************/
                    102: 
                    103: // Show a character on the screen.
                    104: static void
                    105: screenc(char c)
                    106: {
                    107:     struct bregs br;
                    108:     memset(&br, 0, sizeof(br));
                    109:     br.flags = F_IF;
                    110:     br.ah = 0x0e;
                    111:     br.al = c;
                    112:     call16_int(0x10, &br);
                    113: }
                    114: 
                    115: // Handle a character from a printf request.
                    116: static void
                    117: putc_screen(struct putcinfo *action, char c)
                    118: {
                    119:     if (CONFIG_SCREEN_AND_DEBUG)
                    120:         putc_debug(&debuginfo, c);
                    121:     if (c == '\n')
                    122:         screenc('\r');
                    123:     screenc(c);
                    124: }
                    125: 
                    126: static struct putcinfo screeninfo = { putc_screen };
                    127: 
                    128: 
                    129: /****************************************************************
                    130:  * Xprintf code
                    131:  ****************************************************************/
                    132: 
                    133: // Output a character.
                    134: static void
                    135: putc(struct putcinfo *action, char c)
                    136: {
1.1.1.2 ! root      137:     if (MODESEGMENT) {
        !           138:         // Only debugging output supported in segmented mode.
1.1       root      139:         putc_debug(action, c);
                    140:         return;
                    141:     }
                    142: 
                    143:     void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
                    144:     func(action, c);
                    145: }
                    146: 
                    147: // Ouptut a string.
                    148: static void
                    149: puts(struct putcinfo *action, const char *s)
                    150: {
                    151:     for (; *s; s++)
                    152:         putc(action, *s);
                    153: }
                    154: 
                    155: // Output a string that is in the CS segment.
                    156: static void
                    157: puts_cs(struct putcinfo *action, const char *s)
                    158: {
                    159:     char *vs = (char*)s;
                    160:     for (;; vs++) {
                    161:         char c = GET_GLOBAL(*vs);
                    162:         if (!c)
                    163:             break;
                    164:         putc(action, c);
                    165:     }
                    166: }
                    167: 
                    168: // Output an unsigned integer.
                    169: static void
                    170: putuint(struct putcinfo *action, u32 val)
                    171: {
                    172:     char buf[12];
                    173:     char *d = &buf[sizeof(buf) - 1];
                    174:     *d-- = '\0';
                    175:     for (;;) {
                    176:         *d = (val % 10) + '0';
                    177:         val /= 10;
                    178:         if (!val)
                    179:             break;
                    180:         d--;
                    181:     }
                    182:     puts(action, d);
                    183: }
                    184: 
                    185: // Output a single digit hex character.
                    186: static inline void
                    187: putsinglehex(struct putcinfo *action, u32 val)
                    188: {
                    189:     if (val <= 9)
                    190:         val = '0' + val;
                    191:     else
                    192:         val = 'a' + val - 10;
                    193:     putc(action, val);
                    194: }
                    195: 
                    196: // Output an integer in hexadecimal.
                    197: static void
                    198: puthex(struct putcinfo *action, u32 val, int width)
                    199: {
                    200:     if (!width) {
                    201:         u32 tmp = val;
                    202:         width = 1;
                    203:         if (tmp > 0xffff) {
                    204:             width += 4;
                    205:             tmp >>= 16;
                    206:         }
                    207:         if (tmp > 0xff) {
                    208:             width += 2;
                    209:             tmp >>= 8;
                    210:         }
                    211:         if (tmp > 0xf)
                    212:             width += 1;
                    213:     }
                    214: 
                    215:     switch (width) {
                    216:     default: putsinglehex(action, (val >> 28) & 0xf);
                    217:     case 7:  putsinglehex(action, (val >> 24) & 0xf);
                    218:     case 6:  putsinglehex(action, (val >> 20) & 0xf);
                    219:     case 5:  putsinglehex(action, (val >> 16) & 0xf);
                    220:     case 4:  putsinglehex(action, (val >> 12) & 0xf);
                    221:     case 3:  putsinglehex(action, (val >> 8) & 0xf);
                    222:     case 2:  putsinglehex(action, (val >> 4) & 0xf);
                    223:     case 1:  putsinglehex(action, (val >> 0) & 0xf);
                    224:     }
                    225: }
                    226: 
                    227: static inline int
                    228: isdigit(u8 c)
                    229: {
                    230:     return ((u8)(c - '0')) < 10;
                    231: }
                    232: 
                    233: static void
                    234: bvprintf(struct putcinfo *action, const char *fmt, va_list args)
                    235: {
                    236:     const char *s = fmt;
                    237:     for (;; s++) {
                    238:         char c = GET_GLOBAL(*(u8*)s);
                    239:         if (!c)
                    240:             break;
                    241:         if (c != '%') {
                    242:             putc(action, c);
                    243:             continue;
                    244:         }
                    245:         const char *n = s+1;
                    246:         int field_width = 0;
                    247:         for (;;) {
                    248:             c = GET_GLOBAL(*(u8*)n);
                    249:             if (!isdigit(c))
                    250:                 break;
                    251:             field_width = field_width * 10 + c - '0';
                    252:             n++;
                    253:         }
                    254:         if (c == 'l') {
                    255:             // Ignore long format indicator
                    256:             n++;
                    257:             c = GET_GLOBAL(*(u8*)n);
                    258:         }
                    259:         s32 val;
                    260:         const char *sarg;
                    261:         switch (c) {
                    262:         case '%':
                    263:             putc(action, '%');
                    264:             break;
                    265:         case 'd':
                    266:             val = va_arg(args, s32);
                    267:             if (val < 0) {
                    268:                 putc(action, '-');
                    269:                 val = -val;
                    270:             }
                    271:             putuint(action, val);
                    272:             break;
                    273:         case 'u':
                    274:             val = va_arg(args, s32);
                    275:             putuint(action, val);
                    276:             break;
                    277:         case 'p':
                    278:             /* %p always has 0x prepended */
                    279:             putc(action, '0');
                    280:             putc(action, 'x');
                    281:             field_width = 8;
                    282:         case 'x':
                    283:             val = va_arg(args, s32);
                    284:             puthex(action, val, field_width);
                    285:             break;
                    286:         case 'c':
                    287:             val = va_arg(args, int);
                    288:             putc(action, val);
                    289:             break;
                    290:         case '.':
                    291:             // Hack to support "%.s" - meaning string on stack.
                    292:             if (GET_GLOBAL(*(u8*)(n+1)) != 's')
                    293:                 break;
                    294:             n++;
                    295:             sarg = va_arg(args, const char *);
                    296:             puts(action, sarg);
                    297:             break;
                    298:         case 's':
                    299:             sarg = va_arg(args, const char *);
                    300:             puts_cs(action, sarg);
                    301:             break;
                    302:         default:
                    303:             putc(action, '%');
                    304:             n = s;
                    305:         }
                    306:         s = n;
                    307:     }
                    308: }
                    309: 
                    310: void
                    311: panic(const char *fmt, ...)
                    312: {
                    313:     if (CONFIG_DEBUG_LEVEL) {
                    314:         va_list args;
                    315:         va_start(args, fmt);
                    316:         bvprintf(&debuginfo, fmt, args);
                    317:         va_end(args);
                    318:         debug_serial_flush();
                    319:     }
                    320: 
                    321:     // XXX - use PANIC PORT.
                    322:     irq_disable();
                    323:     for (;;)
                    324:         hlt();
                    325: }
                    326: 
                    327: void
                    328: __dprintf(const char *fmt, ...)
                    329: {
1.1.1.2 ! root      330:     if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
1.1       root      331:         && *fmt != '\\' && *fmt != '/') {
                    332:         struct thread_info *cur = getCurThread();
                    333:         if (cur != &MainThread) {
                    334:             // Show "thread id" for this debug message.
                    335:             putc_debug(&debuginfo, '|');
                    336:             puthex(&debuginfo, (u32)cur, 8);
                    337:             putc_debug(&debuginfo, '|');
                    338:             putc_debug(&debuginfo, ' ');
                    339:         }
                    340:     }
                    341: 
                    342:     va_list args;
                    343:     va_start(args, fmt);
                    344:     bvprintf(&debuginfo, fmt, args);
                    345:     va_end(args);
                    346:     debug_serial_flush();
                    347: }
                    348: 
                    349: void
                    350: printf(const char *fmt, ...)
                    351: {
1.1.1.2 ! root      352:     ASSERT32FLAT();
1.1       root      353:     va_list args;
                    354:     va_start(args, fmt);
                    355:     bvprintf(&screeninfo, fmt, args);
                    356:     va_end(args);
                    357:     if (CONFIG_SCREEN_AND_DEBUG)
                    358:         debug_serial_flush();
                    359: }
                    360: 
                    361: 
                    362: /****************************************************************
                    363:  * snprintf
                    364:  ****************************************************************/
                    365: 
                    366: struct snprintfinfo {
                    367:     struct putcinfo info;
                    368:     char *str, *end;
                    369: };
                    370: 
                    371: static void
                    372: putc_str(struct putcinfo *info, char c)
                    373: {
                    374:     struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
                    375:     if (sinfo->str >= sinfo->end)
                    376:         return;
                    377:     *sinfo->str = c;
                    378:     sinfo->str++;
                    379: }
                    380: 
                    381: // Build a formatted string.  Note, this function returns the actual
                    382: // number of bytes used (not including null) even in the overflow
                    383: // case.
                    384: int
                    385: snprintf(char *str, size_t size, const char *fmt, ...)
                    386: {
1.1.1.2 ! root      387:     ASSERT32FLAT();
1.1       root      388:     if (!size)
                    389:         return 0;
                    390:     struct snprintfinfo sinfo = { { putc_str }, str, str + size };
                    391:     va_list args;
                    392:     va_start(args, fmt);
                    393:     bvprintf(&sinfo.info, fmt, args);
                    394:     va_end(args);
                    395:     char *end = sinfo.str;
                    396:     if (end >= sinfo.end)
                    397:         end = sinfo.end - 1;
                    398:     *end = '\0';
                    399:     return end - str;
                    400: }
                    401: 
                    402: 
                    403: /****************************************************************
                    404:  * Misc helpers
                    405:  ****************************************************************/
                    406: 
                    407: void
                    408: hexdump(const void *d, int len)
                    409: {
                    410:     int count=0;
                    411:     while (len > 0) {
                    412:         if (count % 8 == 0) {
                    413:             putc(&debuginfo, '\n');
                    414:             puthex(&debuginfo, count*4, 8);
                    415:             putc(&debuginfo, ':');
                    416:         } else {
                    417:             putc(&debuginfo, ' ');
                    418:         }
                    419:         puthex(&debuginfo, *(u32*)d, 8);
                    420:         count++;
                    421:         len-=4;
                    422:         d+=4;
                    423:     }
                    424:     putc(&debuginfo, '\n');
                    425:     debug_serial_flush();
                    426: }
                    427: 
                    428: static void
                    429: dump_regs(struct bregs *regs)
                    430: {
                    431:     if (!regs) {
                    432:         dprintf(1, "  NULL\n");
                    433:         return;
                    434:     }
                    435:     dprintf(1, "   a=%08x  b=%08x  c=%08x  d=%08x ds=%04x es=%04x ss=%04x\n"
                    436:             , regs->eax, regs->ebx, regs->ecx, regs->edx
                    437:             , regs->ds, regs->es, GET_SEG(SS));
                    438:     dprintf(1, "  si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x  f=%04x\n"
                    439:             , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
                    440:             , regs->code.seg, regs->code.offset, regs->flags);
                    441: }
                    442: 
                    443: // Report entry to an Interrupt Service Routine (ISR).
                    444: void
                    445: __debug_isr(const char *fname)
                    446: {
                    447:     puts_cs(&debuginfo, fname);
                    448:     putc(&debuginfo, '\n');
                    449:     debug_serial_flush();
                    450: }
                    451: 
                    452: // Function called on handler startup.
                    453: void
                    454: __debug_enter(struct bregs *regs, const char *fname)
                    455: {
                    456:     dprintf(1, "enter %s:\n", fname);
                    457:     dump_regs(regs);
                    458: }
                    459: 
                    460: // Send debugging output info.
                    461: void
                    462: __debug_stub(struct bregs *regs, int lineno, const char *fname)
                    463: {
                    464:     dprintf(1, "stub %s:%d:\n", fname, lineno);
                    465:     dump_regs(regs);
                    466: }
                    467: 
                    468: // Report on an invalid parameter.
                    469: void
                    470: __warn_invalid(struct bregs *regs, int lineno, const char *fname)
                    471: {
                    472:     if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
                    473:         dprintf(1, "invalid %s:%d:\n", fname, lineno);
                    474:         dump_regs(regs);
                    475:     }
                    476: }
                    477: 
                    478: // Report on an unimplemented feature.
                    479: void
                    480: __warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
                    481: {
                    482:     if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
                    483:         dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
                    484:         dump_regs(regs);
                    485:     }
                    486: }
                    487: 
                    488: // Report a handler reporting an invalid parameter to the caller.
                    489: void
                    490: __set_invalid(struct bregs *regs, int lineno, const char *fname)
                    491: {
                    492:     __warn_invalid(regs, lineno, fname);
                    493:     set_invalid_silent(regs);
                    494: }
                    495: 
                    496: // Report a call of an unimplemented function.
                    497: void
                    498: __set_unimplemented(struct bregs *regs, int lineno, const char *fname)
                    499: {
                    500:     __warn_unimplemented(regs, lineno, fname);
                    501:     set_invalid_silent(regs);
                    502: }
                    503: 
                    504: // Report a handler reporting an invalid parameter code to the
                    505: // caller.  Note, the lineno and return code are encoded in the same
                    506: // parameter as gcc does a better job of scheduling function calls
                    507: // when there are 3 or less parameters.
                    508: void
                    509: __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
                    510: {
                    511:     u8 code = linecode;
                    512:     u32 lineno = linecode >> 8;
                    513:     __warn_invalid(regs, lineno, fname);
                    514:     set_code_invalid_silent(regs, code);
                    515: }
                    516: 
                    517: // Report a call of an unimplemented function.
                    518: void
                    519: __set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
                    520: {
                    521:     u8 code = linecode;
                    522:     u32 lineno = linecode >> 8;
                    523:     __warn_unimplemented(regs, lineno, fname);
                    524:     set_code_invalid_silent(regs, code);
                    525: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.