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

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)&regs[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: }

unix.superglobalmegacorp.com

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