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