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

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_TIMEOUT 100000
                     25: 
                     26: void
1.1.1.2   root       27: debug_serial_setup(void)
1.1       root       28: {
                     29:     if (!CONFIG_DEBUG_SERIAL)
                     30:         return;
                     31:     // setup for serial logging: 8N1
                     32:     u8 oldparam, newparam = 0x03;
1.1.1.5   root       33:     oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
                     34:     outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
1.1       root       35:     // Disable irqs
                     36:     u8 oldier, newier = 0;
1.1.1.5   root       37:     oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
                     38:     outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
1.1       root       39: 
                     40:     if (oldparam != newparam || oldier != newier)
                     41:         dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
                     42:                 , oldparam, oldier, newparam, newier);
                     43: }
                     44: 
                     45: // Write a character to the serial port.
                     46: static void
                     47: debug_serial(char c)
                     48: {
                     49:     if (!CONFIG_DEBUG_SERIAL)
                     50:         return;
                     51:     int timeout = DEBUG_TIMEOUT;
1.1.1.5   root       52:     while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
1.1       root       53:         if (!timeout--)
                     54:             // Ran out of time.
                     55:             return;
1.1.1.5   root       56:     outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
1.1       root       57: }
                     58: 
                     59: // Make sure all serial port writes have been completely sent.
                     60: static void
1.1.1.2   root       61: debug_serial_flush(void)
1.1       root       62: {
                     63:     if (!CONFIG_DEBUG_SERIAL)
                     64:         return;
                     65:     int timeout = DEBUG_TIMEOUT;
1.1.1.5   root       66:     while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
1.1       root       67:         if (!timeout--)
                     68:             // Ran out of time.
                     69:             return;
                     70: }
                     71: 
                     72: // Write a character to debug port(s).
                     73: static void
                     74: putc_debug(struct putcinfo *action, char c)
                     75: {
                     76:     if (! CONFIG_DEBUG_LEVEL)
                     77:         return;
1.1.1.6 ! root       78:     if (CONFIG_DEBUG_IO)
1.1       root       79:         // Send character to debug port.
1.1.1.6 ! root       80:         outb(c, CONFIG_DEBUG_IO_PORT);
1.1       root       81:     if (c == '\n')
                     82:         debug_serial('\r');
                     83:     debug_serial(c);
                     84: }
                     85: 
1.1.1.2   root       86: // In segmented mode just need a dummy variable (putc_debug is always
                     87: // used anyway), and in 32bit flat mode need a pointer to the 32bit
                     88: // instance of putc_debug().
1.1       root       89: #if MODE16
                     90: static struct putcinfo debuginfo VAR16;
1.1.1.2   root       91: #elif MODESEGMENT
                     92: static struct putcinfo debuginfo VAR32SEG;
1.1       root       93: #else
                     94: static struct putcinfo debuginfo = { putc_debug };
                     95: #endif
                     96: 
                     97: 
                     98: /****************************************************************
                     99:  * Screen writing
                    100:  ****************************************************************/
                    101: 
                    102: // Show a character on the screen.
                    103: static void
                    104: screenc(char c)
                    105: {
                    106:     struct bregs br;
                    107:     memset(&br, 0, sizeof(br));
                    108:     br.flags = F_IF;
                    109:     br.ah = 0x0e;
                    110:     br.al = c;
                    111:     call16_int(0x10, &br);
                    112: }
                    113: 
                    114: // Handle a character from a printf request.
                    115: static void
                    116: putc_screen(struct putcinfo *action, char c)
                    117: {
1.1.1.5   root      118:     if (ScreenAndDebug)
1.1       root      119:         putc_debug(&debuginfo, c);
                    120:     if (c == '\n')
                    121:         screenc('\r');
                    122:     screenc(c);
                    123: }
                    124: 
                    125: static struct putcinfo screeninfo = { putc_screen };
                    126: 
                    127: 
                    128: /****************************************************************
                    129:  * Xprintf code
                    130:  ****************************************************************/
                    131: 
                    132: // Output a character.
                    133: static void
                    134: putc(struct putcinfo *action, char c)
                    135: {
1.1.1.2   root      136:     if (MODESEGMENT) {
                    137:         // Only debugging output supported in segmented mode.
1.1       root      138:         putc_debug(action, c);
                    139:         return;
                    140:     }
                    141: 
                    142:     void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
                    143:     func(action, c);
                    144: }
                    145: 
                    146: // Ouptut a string.
                    147: static void
                    148: puts(struct putcinfo *action, const char *s)
                    149: {
1.1.1.4   root      150:     if (!MODESEGMENT && !s)
                    151:         s = "(NULL)";
1.1       root      152:     for (; *s; s++)
                    153:         putc(action, *s);
                    154: }
                    155: 
                    156: // Output a string that is in the CS segment.
                    157: static void
                    158: puts_cs(struct putcinfo *action, const char *s)
                    159: {
                    160:     char *vs = (char*)s;
                    161:     for (;; vs++) {
                    162:         char c = GET_GLOBAL(*vs);
                    163:         if (!c)
                    164:             break;
                    165:         putc(action, c);
                    166:     }
                    167: }
                    168: 
                    169: // Output an unsigned integer.
                    170: static void
                    171: putuint(struct putcinfo *action, u32 val)
                    172: {
                    173:     char buf[12];
                    174:     char *d = &buf[sizeof(buf) - 1];
                    175:     *d-- = '\0';
                    176:     for (;;) {
                    177:         *d = (val % 10) + '0';
                    178:         val /= 10;
                    179:         if (!val)
                    180:             break;
                    181:         d--;
                    182:     }
                    183:     puts(action, d);
                    184: }
                    185: 
                    186: // Output a single digit hex character.
                    187: static inline void
                    188: putsinglehex(struct putcinfo *action, u32 val)
                    189: {
                    190:     if (val <= 9)
                    191:         val = '0' + val;
                    192:     else
                    193:         val = 'a' + val - 10;
                    194:     putc(action, val);
                    195: }
                    196: 
1.1.1.6 ! root      197: // Output an integer in hexadecimal with a specified width.
1.1       root      198: static void
1.1.1.6 ! root      199: puthex(struct putcinfo *action, u32 val, int width)
1.1       root      200: {
                    201:     switch (width) {
                    202:     default: putsinglehex(action, (val >> 28) & 0xf);
                    203:     case 7:  putsinglehex(action, (val >> 24) & 0xf);
                    204:     case 6:  putsinglehex(action, (val >> 20) & 0xf);
                    205:     case 5:  putsinglehex(action, (val >> 16) & 0xf);
                    206:     case 4:  putsinglehex(action, (val >> 12) & 0xf);
                    207:     case 3:  putsinglehex(action, (val >> 8) & 0xf);
                    208:     case 2:  putsinglehex(action, (val >> 4) & 0xf);
                    209:     case 1:  putsinglehex(action, (val >> 0) & 0xf);
                    210:     }
                    211: }
                    212: 
1.1.1.6 ! root      213: // Output an integer in hexadecimal with a minimum width.
        !           214: static void
        !           215: putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
        !           216: {
        !           217:     u32 tmp = val;
        !           218:     int count = 1;
        !           219:     while (tmp >>= 4)
        !           220:         count++;
        !           221:     width -= count;
        !           222:     while (width-- > 0)
        !           223:         putc(action, padchar);
        !           224:     puthex(action, val, count);
        !           225: }
        !           226: 
1.1       root      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;
1.1.1.6 ! root      247:         char padchar = ' ';
        !           248:         u8 is64 = 0;
1.1       root      249:         for (;;) {
                    250:             c = GET_GLOBAL(*(u8*)n);
                    251:             if (!isdigit(c))
                    252:                 break;
1.1.1.3   root      253:             if (!field_width && (c == '0'))
1.1.1.6 ! root      254:                 padchar = '0';
1.1.1.3   root      255:             else
                    256:                 field_width = field_width * 10 + c - '0';
1.1       root      257:             n++;
                    258:         }
                    259:         if (c == 'l') {
                    260:             // Ignore long format indicator
                    261:             n++;
                    262:             c = GET_GLOBAL(*(u8*)n);
                    263:         }
1.1.1.6 ! root      264:         if (c == 'l') {
        !           265:             is64 = 1;
        !           266:             n++;
        !           267:             c = GET_GLOBAL(*(u8*)n);
        !           268:         }
1.1       root      269:         s32 val;
                    270:         const char *sarg;
                    271:         switch (c) {
                    272:         case '%':
                    273:             putc(action, '%');
                    274:             break;
                    275:         case 'd':
                    276:             val = va_arg(args, s32);
1.1.1.6 ! root      277:             if (is64)
        !           278:                 va_arg(args, s32);
1.1       root      279:             if (val < 0) {
                    280:                 putc(action, '-');
                    281:                 val = -val;
                    282:             }
                    283:             putuint(action, val);
                    284:             break;
                    285:         case 'u':
                    286:             val = va_arg(args, s32);
1.1.1.6 ! root      287:             if (is64)
        !           288:                 va_arg(args, s32);
1.1       root      289:             putuint(action, val);
                    290:             break;
                    291:         case 'p':
1.1.1.6 ! root      292:             val = va_arg(args, s32);
1.1       root      293:             putc(action, '0');
                    294:             putc(action, 'x');
1.1.1.6 ! root      295:             puthex(action, val, 8);
        !           296:             break;
1.1       root      297:         case 'x':
                    298:             val = va_arg(args, s32);
1.1.1.6 ! root      299:             if (is64) {
        !           300:                 u32 upper = va_arg(args, s32);
        !           301:                 if (upper) {
        !           302:                     putprettyhex(action, upper, field_width - 8, padchar);
        !           303:                     puthex(action, val, 8);
        !           304:                     break;
        !           305:                 }
        !           306:             }
        !           307:             putprettyhex(action, val, field_width, padchar);
1.1       root      308:             break;
                    309:         case 'c':
                    310:             val = va_arg(args, int);
                    311:             putc(action, val);
                    312:             break;
                    313:         case '.':
                    314:             // Hack to support "%.s" - meaning string on stack.
                    315:             if (GET_GLOBAL(*(u8*)(n+1)) != 's')
                    316:                 break;
                    317:             n++;
                    318:             sarg = va_arg(args, const char *);
                    319:             puts(action, sarg);
                    320:             break;
                    321:         case 's':
                    322:             sarg = va_arg(args, const char *);
                    323:             puts_cs(action, sarg);
                    324:             break;
                    325:         default:
                    326:             putc(action, '%');
                    327:             n = s;
                    328:         }
                    329:         s = n;
                    330:     }
                    331: }
                    332: 
                    333: void
                    334: panic(const char *fmt, ...)
                    335: {
                    336:     if (CONFIG_DEBUG_LEVEL) {
                    337:         va_list args;
                    338:         va_start(args, fmt);
                    339:         bvprintf(&debuginfo, fmt, args);
                    340:         va_end(args);
                    341:         debug_serial_flush();
                    342:     }
                    343: 
                    344:     // XXX - use PANIC PORT.
                    345:     irq_disable();
                    346:     for (;;)
                    347:         hlt();
                    348: }
                    349: 
                    350: void
                    351: __dprintf(const char *fmt, ...)
                    352: {
1.1.1.2   root      353:     if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
1.1       root      354:         && *fmt != '\\' && *fmt != '/') {
                    355:         struct thread_info *cur = getCurThread();
                    356:         if (cur != &MainThread) {
                    357:             // Show "thread id" for this debug message.
                    358:             putc_debug(&debuginfo, '|');
1.1.1.6 ! root      359:             puthex(&debuginfo, (u32)cur, 8);
1.1       root      360:             putc_debug(&debuginfo, '|');
                    361:             putc_debug(&debuginfo, ' ');
                    362:         }
                    363:     }
                    364: 
                    365:     va_list args;
                    366:     va_start(args, fmt);
                    367:     bvprintf(&debuginfo, fmt, args);
                    368:     va_end(args);
                    369:     debug_serial_flush();
                    370: }
                    371: 
                    372: void
                    373: printf(const char *fmt, ...)
                    374: {
1.1.1.2   root      375:     ASSERT32FLAT();
1.1       root      376:     va_list args;
                    377:     va_start(args, fmt);
                    378:     bvprintf(&screeninfo, fmt, args);
                    379:     va_end(args);
1.1.1.5   root      380:     if (ScreenAndDebug)
1.1       root      381:         debug_serial_flush();
                    382: }
                    383: 
                    384: 
                    385: /****************************************************************
                    386:  * snprintf
                    387:  ****************************************************************/
                    388: 
                    389: struct snprintfinfo {
                    390:     struct putcinfo info;
                    391:     char *str, *end;
                    392: };
                    393: 
                    394: static void
                    395: putc_str(struct putcinfo *info, char c)
                    396: {
                    397:     struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
                    398:     if (sinfo->str >= sinfo->end)
                    399:         return;
                    400:     *sinfo->str = c;
                    401:     sinfo->str++;
                    402: }
                    403: 
                    404: // Build a formatted string.  Note, this function returns the actual
                    405: // number of bytes used (not including null) even in the overflow
                    406: // case.
                    407: int
                    408: snprintf(char *str, size_t size, const char *fmt, ...)
                    409: {
1.1.1.2   root      410:     ASSERT32FLAT();
1.1       root      411:     if (!size)
                    412:         return 0;
                    413:     struct snprintfinfo sinfo = { { putc_str }, str, str + size };
                    414:     va_list args;
                    415:     va_start(args, fmt);
                    416:     bvprintf(&sinfo.info, fmt, args);
                    417:     va_end(args);
                    418:     char *end = sinfo.str;
                    419:     if (end >= sinfo.end)
                    420:         end = sinfo.end - 1;
                    421:     *end = '\0';
                    422:     return end - str;
                    423: }
                    424: 
1.1.1.4   root      425: // Build a formatted string - malloc'ing the memory.
                    426: char *
                    427: znprintf(size_t size, const char *fmt, ...)
                    428: {
                    429:     ASSERT32FLAT();
                    430:     if (!size)
                    431:         return NULL;
                    432:     char *str = malloc_tmp(size);
                    433:     if (!str) {
                    434:         warn_noalloc();
                    435:         return NULL;
                    436:     }
                    437:     struct snprintfinfo sinfo = { { putc_str }, str, str + size };
                    438:     va_list args;
                    439:     va_start(args, fmt);
                    440:     bvprintf(&sinfo.info, fmt, args);
                    441:     va_end(args);
                    442:     char *end = sinfo.str;
                    443:     if (end >= sinfo.end)
                    444:         end = sinfo.end - 1;
                    445:     *end = '\0';
                    446:     return str;
                    447: }
                    448: 
1.1       root      449: 
                    450: /****************************************************************
                    451:  * Misc helpers
                    452:  ****************************************************************/
                    453: 
                    454: void
                    455: hexdump(const void *d, int len)
                    456: {
                    457:     int count=0;
                    458:     while (len > 0) {
                    459:         if (count % 8 == 0) {
                    460:             putc(&debuginfo, '\n');
1.1.1.6 ! root      461:             puthex(&debuginfo, count*4, 8);
1.1       root      462:             putc(&debuginfo, ':');
                    463:         } else {
                    464:             putc(&debuginfo, ' ');
                    465:         }
1.1.1.6 ! root      466:         puthex(&debuginfo, *(u32*)d, 8);
1.1       root      467:         count++;
                    468:         len-=4;
                    469:         d+=4;
                    470:     }
                    471:     putc(&debuginfo, '\n');
                    472:     debug_serial_flush();
                    473: }
                    474: 
                    475: static void
                    476: dump_regs(struct bregs *regs)
                    477: {
                    478:     if (!regs) {
                    479:         dprintf(1, "  NULL\n");
                    480:         return;
                    481:     }
                    482:     dprintf(1, "   a=%08x  b=%08x  c=%08x  d=%08x ds=%04x es=%04x ss=%04x\n"
                    483:             , regs->eax, regs->ebx, regs->ecx, regs->edx
                    484:             , regs->ds, regs->es, GET_SEG(SS));
                    485:     dprintf(1, "  si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x  f=%04x\n"
                    486:             , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
                    487:             , regs->code.seg, regs->code.offset, regs->flags);
                    488: }
                    489: 
                    490: // Report entry to an Interrupt Service Routine (ISR).
                    491: void
                    492: __debug_isr(const char *fname)
                    493: {
                    494:     puts_cs(&debuginfo, fname);
                    495:     putc(&debuginfo, '\n');
                    496:     debug_serial_flush();
                    497: }
                    498: 
                    499: // Function called on handler startup.
                    500: void
                    501: __debug_enter(struct bregs *regs, const char *fname)
                    502: {
                    503:     dprintf(1, "enter %s:\n", fname);
                    504:     dump_regs(regs);
                    505: }
                    506: 
                    507: // Send debugging output info.
                    508: void
                    509: __debug_stub(struct bregs *regs, int lineno, const char *fname)
                    510: {
                    511:     dprintf(1, "stub %s:%d:\n", fname, lineno);
                    512:     dump_regs(regs);
                    513: }
                    514: 
                    515: // Report on an invalid parameter.
                    516: void
                    517: __warn_invalid(struct bregs *regs, int lineno, const char *fname)
                    518: {
                    519:     if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
                    520:         dprintf(1, "invalid %s:%d:\n", fname, lineno);
                    521:         dump_regs(regs);
                    522:     }
                    523: }
                    524: 
                    525: // Report on an unimplemented feature.
                    526: void
                    527: __warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
                    528: {
                    529:     if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
                    530:         dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
                    531:         dump_regs(regs);
                    532:     }
                    533: }
                    534: 
1.1.1.3   root      535: // Report a detected internal inconsistency.
                    536: void
                    537: __warn_internalerror(int lineno, const char *fname)
                    538: {
                    539:     dprintf(1, "WARNING - internal error detected at %s:%d!\n"
                    540:             , fname, lineno);
                    541: }
                    542: 
                    543: // Report on an allocation failure.
                    544: void
                    545: __warn_noalloc(int lineno, const char *fname)
                    546: {
                    547:     dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
                    548:             , fname, lineno);
                    549: }
                    550: 
                    551: // Report on a timeout exceeded.
                    552: void
                    553: __warn_timeout(int lineno, const char *fname)
                    554: {
                    555:     dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
                    556: }
                    557: 
1.1       root      558: // Report a handler reporting an invalid parameter to the caller.
                    559: void
                    560: __set_invalid(struct bregs *regs, int lineno, const char *fname)
                    561: {
                    562:     __warn_invalid(regs, lineno, fname);
                    563:     set_invalid_silent(regs);
                    564: }
                    565: 
                    566: // Report a call of an unimplemented function.
                    567: void
                    568: __set_unimplemented(struct bregs *regs, int lineno, const char *fname)
                    569: {
                    570:     __warn_unimplemented(regs, lineno, fname);
                    571:     set_invalid_silent(regs);
                    572: }
                    573: 
                    574: // Report a handler reporting an invalid parameter code to the
                    575: // caller.  Note, the lineno and return code are encoded in the same
                    576: // parameter as gcc does a better job of scheduling function calls
                    577: // when there are 3 or less parameters.
                    578: void
                    579: __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
                    580: {
                    581:     u8 code = linecode;
                    582:     u32 lineno = linecode >> 8;
                    583:     __warn_invalid(regs, lineno, fname);
                    584:     set_code_invalid_silent(regs, code);
                    585: }
                    586: 
                    587: // Report a call of an unimplemented function.
                    588: void
                    589: __set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
                    590: {
                    591:     u8 code = linecode;
                    592:     u32 lineno = linecode >> 8;
                    593:     __warn_unimplemented(regs, lineno, fname);
                    594:     set_code_invalid_silent(regs, code);
                    595: }

unix.superglobalmegacorp.com

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