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