|
|
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
1.1.1.3 ! root 198: puthex(struct putcinfo *action, u32 val, int width, int spacepad)
1.1 root 199: {
200: if (!width) {
201: u32 tmp = val;
202: width = 1;
1.1.1.3 ! root 203: while (tmp >>= 4)
! 204: width++;
! 205: } else if (spacepad) {
! 206: u32 tmp = val;
! 207: u32 count = 1;
! 208: while (tmp >>= 4)
! 209: count++;
! 210: if (width > count) {
! 211: count = width - count;
! 212: width -= count;
! 213: while (count--)
! 214: putc(action, ' ');
1.1 root 215: }
216: }
217:
218: switch (width) {
219: default: putsinglehex(action, (val >> 28) & 0xf);
220: case 7: putsinglehex(action, (val >> 24) & 0xf);
221: case 6: putsinglehex(action, (val >> 20) & 0xf);
222: case 5: putsinglehex(action, (val >> 16) & 0xf);
223: case 4: putsinglehex(action, (val >> 12) & 0xf);
224: case 3: putsinglehex(action, (val >> 8) & 0xf);
225: case 2: putsinglehex(action, (val >> 4) & 0xf);
226: case 1: putsinglehex(action, (val >> 0) & 0xf);
227: }
228: }
229:
230: static inline int
231: isdigit(u8 c)
232: {
233: return ((u8)(c - '0')) < 10;
234: }
235:
236: static void
237: bvprintf(struct putcinfo *action, const char *fmt, va_list args)
238: {
239: const char *s = fmt;
240: for (;; s++) {
241: char c = GET_GLOBAL(*(u8*)s);
242: if (!c)
243: break;
244: if (c != '%') {
245: putc(action, c);
246: continue;
247: }
248: const char *n = s+1;
249: int field_width = 0;
1.1.1.3 ! root 250: int spacepad = 1;
1.1 root 251: for (;;) {
252: c = GET_GLOBAL(*(u8*)n);
253: if (!isdigit(c))
254: break;
1.1.1.3 ! root 255: if (!field_width && (c == '0'))
! 256: spacepad = 0;
! 257: else
! 258: field_width = field_width * 10 + c - '0';
1.1 root 259: n++;
260: }
261: if (c == 'l') {
262: // Ignore long format indicator
263: n++;
264: c = GET_GLOBAL(*(u8*)n);
265: }
266: s32 val;
267: const char *sarg;
268: switch (c) {
269: case '%':
270: putc(action, '%');
271: break;
272: case 'd':
273: val = va_arg(args, s32);
274: if (val < 0) {
275: putc(action, '-');
276: val = -val;
277: }
278: putuint(action, val);
279: break;
280: case 'u':
281: val = va_arg(args, s32);
282: putuint(action, val);
283: break;
284: case 'p':
285: /* %p always has 0x prepended */
286: putc(action, '0');
287: putc(action, 'x');
288: field_width = 8;
1.1.1.3 ! root 289: spacepad = 0;
1.1 root 290: case 'x':
291: val = va_arg(args, s32);
1.1.1.3 ! root 292: puthex(action, val, field_width, spacepad);
1.1 root 293: break;
294: case 'c':
295: val = va_arg(args, int);
296: putc(action, val);
297: break;
298: case '.':
299: // Hack to support "%.s" - meaning string on stack.
300: if (GET_GLOBAL(*(u8*)(n+1)) != 's')
301: break;
302: n++;
303: sarg = va_arg(args, const char *);
304: puts(action, sarg);
305: break;
306: case 's':
307: sarg = va_arg(args, const char *);
308: puts_cs(action, sarg);
309: break;
310: default:
311: putc(action, '%');
312: n = s;
313: }
314: s = n;
315: }
316: }
317:
318: void
319: panic(const char *fmt, ...)
320: {
321: if (CONFIG_DEBUG_LEVEL) {
322: va_list args;
323: va_start(args, fmt);
324: bvprintf(&debuginfo, fmt, args);
325: va_end(args);
326: debug_serial_flush();
327: }
328:
329: // XXX - use PANIC PORT.
330: irq_disable();
331: for (;;)
332: hlt();
333: }
334:
335: void
336: __dprintf(const char *fmt, ...)
337: {
1.1.1.2 root 338: if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
1.1 root 339: && *fmt != '\\' && *fmt != '/') {
340: struct thread_info *cur = getCurThread();
341: if (cur != &MainThread) {
342: // Show "thread id" for this debug message.
343: putc_debug(&debuginfo, '|');
1.1.1.3 ! root 344: puthex(&debuginfo, (u32)cur, 8, 0);
1.1 root 345: putc_debug(&debuginfo, '|');
346: putc_debug(&debuginfo, ' ');
347: }
348: }
349:
350: va_list args;
351: va_start(args, fmt);
352: bvprintf(&debuginfo, fmt, args);
353: va_end(args);
354: debug_serial_flush();
355: }
356:
357: void
358: printf(const char *fmt, ...)
359: {
1.1.1.2 root 360: ASSERT32FLAT();
1.1 root 361: va_list args;
362: va_start(args, fmt);
363: bvprintf(&screeninfo, fmt, args);
364: va_end(args);
365: if (CONFIG_SCREEN_AND_DEBUG)
366: debug_serial_flush();
367: }
368:
369:
370: /****************************************************************
371: * snprintf
372: ****************************************************************/
373:
374: struct snprintfinfo {
375: struct putcinfo info;
376: char *str, *end;
377: };
378:
379: static void
380: putc_str(struct putcinfo *info, char c)
381: {
382: struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
383: if (sinfo->str >= sinfo->end)
384: return;
385: *sinfo->str = c;
386: sinfo->str++;
387: }
388:
389: // Build a formatted string. Note, this function returns the actual
390: // number of bytes used (not including null) even in the overflow
391: // case.
392: int
393: snprintf(char *str, size_t size, const char *fmt, ...)
394: {
1.1.1.2 root 395: ASSERT32FLAT();
1.1 root 396: if (!size)
397: return 0;
398: struct snprintfinfo sinfo = { { putc_str }, str, str + size };
399: va_list args;
400: va_start(args, fmt);
401: bvprintf(&sinfo.info, fmt, args);
402: va_end(args);
403: char *end = sinfo.str;
404: if (end >= sinfo.end)
405: end = sinfo.end - 1;
406: *end = '\0';
407: return end - str;
408: }
409:
410:
411: /****************************************************************
412: * Misc helpers
413: ****************************************************************/
414:
415: void
416: hexdump(const void *d, int len)
417: {
418: int count=0;
419: while (len > 0) {
420: if (count % 8 == 0) {
421: putc(&debuginfo, '\n');
1.1.1.3 ! root 422: puthex(&debuginfo, count*4, 8, 0);
1.1 root 423: putc(&debuginfo, ':');
424: } else {
425: putc(&debuginfo, ' ');
426: }
1.1.1.3 ! root 427: puthex(&debuginfo, *(u32*)d, 8, 0);
1.1 root 428: count++;
429: len-=4;
430: d+=4;
431: }
432: putc(&debuginfo, '\n');
433: debug_serial_flush();
434: }
435:
436: static void
437: dump_regs(struct bregs *regs)
438: {
439: if (!regs) {
440: dprintf(1, " NULL\n");
441: return;
442: }
443: dprintf(1, " a=%08x b=%08x c=%08x d=%08x ds=%04x es=%04x ss=%04x\n"
444: , regs->eax, regs->ebx, regs->ecx, regs->edx
445: , regs->ds, regs->es, GET_SEG(SS));
446: dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
447: , regs->esi, regs->edi, regs->ebp, (u32)®s[1]
448: , regs->code.seg, regs->code.offset, regs->flags);
449: }
450:
451: // Report entry to an Interrupt Service Routine (ISR).
452: void
453: __debug_isr(const char *fname)
454: {
455: puts_cs(&debuginfo, fname);
456: putc(&debuginfo, '\n');
457: debug_serial_flush();
458: }
459:
460: // Function called on handler startup.
461: void
462: __debug_enter(struct bregs *regs, const char *fname)
463: {
464: dprintf(1, "enter %s:\n", fname);
465: dump_regs(regs);
466: }
467:
468: // Send debugging output info.
469: void
470: __debug_stub(struct bregs *regs, int lineno, const char *fname)
471: {
472: dprintf(1, "stub %s:%d:\n", fname, lineno);
473: dump_regs(regs);
474: }
475:
476: // Report on an invalid parameter.
477: void
478: __warn_invalid(struct bregs *regs, int lineno, const char *fname)
479: {
480: if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
481: dprintf(1, "invalid %s:%d:\n", fname, lineno);
482: dump_regs(regs);
483: }
484: }
485:
486: // Report on an unimplemented feature.
487: void
488: __warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
489: {
490: if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
491: dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
492: dump_regs(regs);
493: }
494: }
495:
1.1.1.3 ! root 496: // Report a detected internal inconsistency.
! 497: void
! 498: __warn_internalerror(int lineno, const char *fname)
! 499: {
! 500: dprintf(1, "WARNING - internal error detected at %s:%d!\n"
! 501: , fname, lineno);
! 502: }
! 503:
! 504: // Report on an allocation failure.
! 505: void
! 506: __warn_noalloc(int lineno, const char *fname)
! 507: {
! 508: dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
! 509: , fname, lineno);
! 510: }
! 511:
! 512: // Report on a timeout exceeded.
! 513: void
! 514: __warn_timeout(int lineno, const char *fname)
! 515: {
! 516: dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
! 517: }
! 518:
1.1 root 519: // Report a handler reporting an invalid parameter to the caller.
520: void
521: __set_invalid(struct bregs *regs, int lineno, const char *fname)
522: {
523: __warn_invalid(regs, lineno, fname);
524: set_invalid_silent(regs);
525: }
526:
527: // Report a call of an unimplemented function.
528: void
529: __set_unimplemented(struct bregs *regs, int lineno, const char *fname)
530: {
531: __warn_unimplemented(regs, lineno, fname);
532: set_invalid_silent(regs);
533: }
534:
535: // Report a handler reporting an invalid parameter code to the
536: // caller. Note, the lineno and return code are encoded in the same
537: // parameter as gcc does a better job of scheduling function calls
538: // when there are 3 or less parameters.
539: void
540: __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
541: {
542: u8 code = linecode;
543: u32 lineno = linecode >> 8;
544: __warn_invalid(regs, lineno, fname);
545: set_code_invalid_silent(regs, code);
546: }
547:
548: // Report a call of an unimplemented function.
549: void
550: __set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
551: {
552: u8 code = linecode;
553: u32 lineno = linecode >> 8;
554: __warn_unimplemented(regs, lineno, fname);
555: set_code_invalid_silent(regs, code);
556: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.