|
|
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)®s[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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.